File reference list

This commit is contained in:
2025-11-18 21:45:13 +08:00
parent 548c9963ee
commit 715ce1a368
7 changed files with 630 additions and 2 deletions

23
lib/models/reference.dart Normal file
View File

@@ -0,0 +1,23 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:island/models/file.dart';
part 'reference.freezed.dart';
part 'reference.g.dart';
@freezed
sealed class Reference with _$Reference {
const factory Reference({
required String id,
@JsonKey(name: 'file_id') required String fileId,
SnCloudFile? file,
required String usage,
@JsonKey(name: 'resource_id') required String resourceId,
@JsonKey(name: 'expired_at') DateTime? expiredAt,
@JsonKey(name: 'created_at') required DateTime createdAt,
@JsonKey(name: 'updated_at') required DateTime updatedAt,
@JsonKey(name: 'deleted_at') DateTime? deletedAt,
}) = _Reference;
factory Reference.fromJson(Map<String, dynamic> json) =>
_$ReferenceFromJson(json);
}

View File

@@ -0,0 +1,319 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'reference.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$Reference {
String get id;@JsonKey(name: 'file_id') String get fileId; SnCloudFile? get file; String get usage;@JsonKey(name: 'resource_id') String get resourceId;@JsonKey(name: 'expired_at') DateTime? get expiredAt;@JsonKey(name: 'created_at') DateTime get createdAt;@JsonKey(name: 'updated_at') DateTime get updatedAt;@JsonKey(name: 'deleted_at') DateTime? get deletedAt;
/// Create a copy of Reference
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$ReferenceCopyWith<Reference> get copyWith => _$ReferenceCopyWithImpl<Reference>(this as Reference, _$identity);
/// Serializes this Reference to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is Reference&&(identical(other.id, id) || other.id == id)&&(identical(other.fileId, fileId) || other.fileId == fileId)&&(identical(other.file, file) || other.file == file)&&(identical(other.usage, usage) || other.usage == usage)&&(identical(other.resourceId, resourceId) || other.resourceId == resourceId)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,fileId,file,usage,resourceId,expiredAt,createdAt,updatedAt,deletedAt);
@override
String toString() {
return 'Reference(id: $id, fileId: $fileId, file: $file, usage: $usage, resourceId: $resourceId, expiredAt: $expiredAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
}
}
/// @nodoc
abstract mixin class $ReferenceCopyWith<$Res> {
factory $ReferenceCopyWith(Reference value, $Res Function(Reference) _then) = _$ReferenceCopyWithImpl;
@useResult
$Res call({
String id,@JsonKey(name: 'file_id') String fileId, SnCloudFile? file, String usage,@JsonKey(name: 'resource_id') String resourceId,@JsonKey(name: 'expired_at') DateTime? expiredAt,@JsonKey(name: 'created_at') DateTime createdAt,@JsonKey(name: 'updated_at') DateTime updatedAt,@JsonKey(name: 'deleted_at') DateTime? deletedAt
});
$SnCloudFileCopyWith<$Res>? get file;
}
/// @nodoc
class _$ReferenceCopyWithImpl<$Res>
implements $ReferenceCopyWith<$Res> {
_$ReferenceCopyWithImpl(this._self, this._then);
final Reference _self;
final $Res Function(Reference) _then;
/// Create a copy of Reference
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? fileId = null,Object? file = freezed,Object? usage = null,Object? resourceId = null,Object? expiredAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
return _then(_self.copyWith(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,fileId: null == fileId ? _self.fileId : fileId // ignore: cast_nullable_to_non_nullable
as String,file: freezed == file ? _self.file : file // ignore: cast_nullable_to_non_nullable
as SnCloudFile?,usage: null == usage ? _self.usage : usage // ignore: cast_nullable_to_non_nullable
as String,resourceId: null == resourceId ? _self.resourceId : resourceId // ignore: cast_nullable_to_non_nullable
as String,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
as DateTime?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
));
}
/// Create a copy of Reference
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnCloudFileCopyWith<$Res>? get file {
if (_self.file == null) {
return null;
}
return $SnCloudFileCopyWith<$Res>(_self.file!, (value) {
return _then(_self.copyWith(file: value));
});
}
}
/// Adds pattern-matching-related methods to [Reference].
extension ReferencePatterns on Reference {
/// 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( _Reference value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _Reference() 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( _Reference value) $default,){
final _that = this;
switch (_that) {
case _Reference():
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( _Reference value)? $default,){
final _that = this;
switch (_that) {
case _Reference() 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( String id, @JsonKey(name: 'file_id') String fileId, SnCloudFile? file, String usage, @JsonKey(name: 'resource_id') String resourceId, @JsonKey(name: 'expired_at') DateTime? expiredAt, @JsonKey(name: 'created_at') DateTime createdAt, @JsonKey(name: 'updated_at') DateTime updatedAt, @JsonKey(name: 'deleted_at') DateTime? deletedAt)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _Reference() when $default != null:
return $default(_that.id,_that.fileId,_that.file,_that.usage,_that.resourceId,_that.expiredAt,_that.createdAt,_that.updatedAt,_that.deletedAt);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( String id, @JsonKey(name: 'file_id') String fileId, SnCloudFile? file, String usage, @JsonKey(name: 'resource_id') String resourceId, @JsonKey(name: 'expired_at') DateTime? expiredAt, @JsonKey(name: 'created_at') DateTime createdAt, @JsonKey(name: 'updated_at') DateTime updatedAt, @JsonKey(name: 'deleted_at') DateTime? deletedAt) $default,) {final _that = this;
switch (_that) {
case _Reference():
return $default(_that.id,_that.fileId,_that.file,_that.usage,_that.resourceId,_that.expiredAt,_that.createdAt,_that.updatedAt,_that.deletedAt);}
}
/// 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( String id, @JsonKey(name: 'file_id') String fileId, SnCloudFile? file, String usage, @JsonKey(name: 'resource_id') String resourceId, @JsonKey(name: 'expired_at') DateTime? expiredAt, @JsonKey(name: 'created_at') DateTime createdAt, @JsonKey(name: 'updated_at') DateTime updatedAt, @JsonKey(name: 'deleted_at') DateTime? deletedAt)? $default,) {final _that = this;
switch (_that) {
case _Reference() when $default != null:
return $default(_that.id,_that.fileId,_that.file,_that.usage,_that.resourceId,_that.expiredAt,_that.createdAt,_that.updatedAt,_that.deletedAt);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _Reference implements Reference {
const _Reference({required this.id, @JsonKey(name: 'file_id') required this.fileId, this.file, required this.usage, @JsonKey(name: 'resource_id') required this.resourceId, @JsonKey(name: 'expired_at') this.expiredAt, @JsonKey(name: 'created_at') required this.createdAt, @JsonKey(name: 'updated_at') required this.updatedAt, @JsonKey(name: 'deleted_at') this.deletedAt});
factory _Reference.fromJson(Map<String, dynamic> json) => _$ReferenceFromJson(json);
@override final String id;
@override@JsonKey(name: 'file_id') final String fileId;
@override final SnCloudFile? file;
@override final String usage;
@override@JsonKey(name: 'resource_id') final String resourceId;
@override@JsonKey(name: 'expired_at') final DateTime? expiredAt;
@override@JsonKey(name: 'created_at') final DateTime createdAt;
@override@JsonKey(name: 'updated_at') final DateTime updatedAt;
@override@JsonKey(name: 'deleted_at') final DateTime? deletedAt;
/// Create a copy of Reference
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$ReferenceCopyWith<_Reference> get copyWith => __$ReferenceCopyWithImpl<_Reference>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$ReferenceToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Reference&&(identical(other.id, id) || other.id == id)&&(identical(other.fileId, fileId) || other.fileId == fileId)&&(identical(other.file, file) || other.file == file)&&(identical(other.usage, usage) || other.usage == usage)&&(identical(other.resourceId, resourceId) || other.resourceId == resourceId)&&(identical(other.expiredAt, expiredAt) || other.expiredAt == expiredAt)&&(identical(other.createdAt, createdAt) || other.createdAt == createdAt)&&(identical(other.updatedAt, updatedAt) || other.updatedAt == updatedAt)&&(identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,id,fileId,file,usage,resourceId,expiredAt,createdAt,updatedAt,deletedAt);
@override
String toString() {
return 'Reference(id: $id, fileId: $fileId, file: $file, usage: $usage, resourceId: $resourceId, expiredAt: $expiredAt, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt)';
}
}
/// @nodoc
abstract mixin class _$ReferenceCopyWith<$Res> implements $ReferenceCopyWith<$Res> {
factory _$ReferenceCopyWith(_Reference value, $Res Function(_Reference) _then) = __$ReferenceCopyWithImpl;
@override @useResult
$Res call({
String id,@JsonKey(name: 'file_id') String fileId, SnCloudFile? file, String usage,@JsonKey(name: 'resource_id') String resourceId,@JsonKey(name: 'expired_at') DateTime? expiredAt,@JsonKey(name: 'created_at') DateTime createdAt,@JsonKey(name: 'updated_at') DateTime updatedAt,@JsonKey(name: 'deleted_at') DateTime? deletedAt
});
@override $SnCloudFileCopyWith<$Res>? get file;
}
/// @nodoc
class __$ReferenceCopyWithImpl<$Res>
implements _$ReferenceCopyWith<$Res> {
__$ReferenceCopyWithImpl(this._self, this._then);
final _Reference _self;
final $Res Function(_Reference) _then;
/// Create a copy of Reference
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? fileId = null,Object? file = freezed,Object? usage = null,Object? resourceId = null,Object? expiredAt = freezed,Object? createdAt = null,Object? updatedAt = null,Object? deletedAt = freezed,}) {
return _then(_Reference(
id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String,fileId: null == fileId ? _self.fileId : fileId // ignore: cast_nullable_to_non_nullable
as String,file: freezed == file ? _self.file : file // ignore: cast_nullable_to_non_nullable
as SnCloudFile?,usage: null == usage ? _self.usage : usage // ignore: cast_nullable_to_non_nullable
as String,resourceId: null == resourceId ? _self.resourceId : resourceId // ignore: cast_nullable_to_non_nullable
as String,expiredAt: freezed == expiredAt ? _self.expiredAt : expiredAt // ignore: cast_nullable_to_non_nullable
as DateTime?,createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,updatedAt: null == updatedAt ? _self.updatedAt : updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable
as DateTime?,
));
}
/// Create a copy of Reference
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$SnCloudFileCopyWith<$Res>? get file {
if (_self.file == null) {
return null;
}
return $SnCloudFileCopyWith<$Res>(_self.file!, (value) {
return _then(_self.copyWith(file: value));
});
}
}
// dart format on

View File

@@ -0,0 +1,41 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'reference.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_Reference _$ReferenceFromJson(Map<String, dynamic> json) => _Reference(
id: json['id'] as String,
fileId: json['file_id'] as String,
file:
json['file'] == null
? null
: SnCloudFile.fromJson(json['file'] as Map<String, dynamic>),
usage: json['usage'] as String,
resourceId: json['resource_id'] as String,
expiredAt:
json['expired_at'] == null
? null
: DateTime.parse(json['expired_at'] as String),
createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt:
json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
);
Map<String, dynamic> _$ReferenceToJson(_Reference instance) =>
<String, dynamic>{
'id': instance.id,
'file_id': instance.fileId,
'file': instance.file?.toJson(),
'usage': instance.usage,
'resource_id': instance.resourceId,
'expired_at': instance.expiredAt?.toIso8601String(),
'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(),
'deleted_at': instance.deletedAt?.toIso8601String(),
};

View File

@@ -45,7 +45,7 @@ final billingQuotaProvider =
// ignore: unused_element // ignore: unused_element
typedef BillingQuotaRef = AutoDisposeFutureProviderRef<Map<String, dynamic>?>; typedef BillingQuotaRef = AutoDisposeFutureProviderRef<Map<String, dynamic>?>;
String _$cloudFileListNotifierHash() => String _$cloudFileListNotifierHash() =>
r'5f2f80357cb31ac6473df5ac2101f9a462004f81'; r'533dfa86f920b60cf7491fb4aeb95ece19e428af';
/// See also [CloudFileListNotifier]. /// See also [CloudFileListNotifier].
@ProviderFor(CloudFileListNotifier) @ProviderFor(CloudFileListNotifier)
@@ -66,7 +66,7 @@ final cloudFileListNotifierProvider = AutoDisposeAsyncNotifierProvider<
typedef _$CloudFileListNotifier = typedef _$CloudFileListNotifier =
AutoDisposeAsyncNotifier<CursorPagingData<FileListItem>>; AutoDisposeAsyncNotifier<CursorPagingData<FileListItem>>;
String _$unindexedFileListNotifierHash() => String _$unindexedFileListNotifierHash() =>
r'48fc92432a50a562190da5fe8ed0920d171b07b6'; r'afa487d7b956b71b21ca1b073a01364a34ede1d5';
/// See also [UnindexedFileListNotifier]. /// See also [UnindexedFileListNotifier].
@ProviderFor(UnindexedFileListNotifier) @ProviderFor(UnindexedFileListNotifier)

View File

@@ -0,0 +1,18 @@
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:island/models/reference.dart';
import 'package:island/pods/network.dart';
part 'file_references.g.dart';
@riverpod
Future<List<Reference>> fileReferences(
FileReferencesRef ref,
String fileId,
) async {
final client = ref.read(apiClientProvider);
final response = await client.get('/drive/files/$fileId/references');
final list = response.data as List<dynamic>;
return list
.map((json) => Reference.fromJson(json as Map<String, dynamic>))
.toList();
}

View File

@@ -0,0 +1,153 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'file_references.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$fileReferencesHash() => r'464562fbdc9452d8a5ffbd2d9d9343cdb43f1876';
/// Copied from Dart SDK
class _SystemHash {
_SystemHash._();
static int combine(int hash, int value) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + value);
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(int hash) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
/// See also [fileReferences].
@ProviderFor(fileReferences)
const fileReferencesProvider = FileReferencesFamily();
/// See also [fileReferences].
class FileReferencesFamily extends Family<AsyncValue<List<Reference>>> {
/// See also [fileReferences].
const FileReferencesFamily();
/// See also [fileReferences].
FileReferencesProvider call(String fileId) {
return FileReferencesProvider(fileId);
}
@override
FileReferencesProvider getProviderOverride(
covariant FileReferencesProvider provider,
) {
return call(provider.fileId);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'fileReferencesProvider';
}
/// See also [fileReferences].
class FileReferencesProvider
extends AutoDisposeFutureProvider<List<Reference>> {
/// See also [fileReferences].
FileReferencesProvider(String fileId)
: this._internal(
(ref) => fileReferences(ref as FileReferencesRef, fileId),
from: fileReferencesProvider,
name: r'fileReferencesProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$fileReferencesHash,
dependencies: FileReferencesFamily._dependencies,
allTransitiveDependencies:
FileReferencesFamily._allTransitiveDependencies,
fileId: fileId,
);
FileReferencesProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.fileId,
}) : super.internal();
final String fileId;
@override
Override overrideWith(
FutureOr<List<Reference>> Function(FileReferencesRef provider) create,
) {
return ProviderOverride(
origin: this,
override: FileReferencesProvider._internal(
(ref) => create(ref as FileReferencesRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
fileId: fileId,
),
);
}
@override
AutoDisposeFutureProviderElement<List<Reference>> createElement() {
return _FileReferencesProviderElement(this);
}
@override
bool operator ==(Object other) {
return other is FileReferencesProvider && other.fileId == fileId;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, fileId.hashCode);
return _SystemHash.finish(hash);
}
}
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
mixin FileReferencesRef on AutoDisposeFutureProviderRef<List<Reference>> {
/// The parameter `fileId` of this provider.
String get fileId;
}
class _FileReferencesProviderElement
extends AutoDisposeFutureProviderElement<List<Reference>>
with FileReferencesRef {
_FileReferencesProviderElement(super.provider);
@override
String get fileId => (origin as FileReferencesProvider).fileId;
}
// 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

View File

@@ -6,19 +6,24 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:gal/gal.dart'; import 'package:gal/gal.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/file.dart'; import 'package:island/models/file.dart';
import 'package:island/pods/config.dart'; import 'package:island/pods/config.dart';
import 'package:island/pods/file_references.dart';
import 'package:island/pods/network.dart'; import 'package:island/pods/network.dart';
import 'package:island/pods/upload_tasks.dart'; import 'package:island/pods/upload_tasks.dart';
import 'package:island/models/drive_task.dart'; import 'package:island/models/drive_task.dart';
import 'package:island/services/responsive.dart'; import 'package:island/services/responsive.dart';
import 'package:island/services/time.dart';
import 'package:island/widgets/alert.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/file_info_sheet.dart'; import 'package:island/widgets/content/file_info_sheet.dart';
import 'package:island/widgets/content/file_viewer_contents.dart'; import 'package:island/widgets/content/file_viewer_contents.dart';
import 'package:island/widgets/content/sheet.dart';
import 'package:path/path.dart' show extension; import 'package:path/path.dart' show extension;
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:styled_widget/styled_widget.dart';
class FileDetailScreen extends HookConsumerWidget { class FileDetailScreen extends HookConsumerWidget {
final SnCloudFile item; final SnCloudFile item;
@@ -167,6 +172,24 @@ class FileDetailScreen extends HookConsumerWidget {
break; break;
} }
// Add references button
actions.add(
IconButton(
icon: Icon(Icons.link),
onPressed:
() => showModalBottomSheet(
useRootNavigator: true,
context: context,
isScrollControlled: true,
builder:
(context) => SheetScaffold(
titleText: 'File References',
child: ReferencesList(fileId: item.id),
),
),
),
);
// Always add info button // Always add info button
actions.add( actions.add(
IconButton(icon: Icon(Icons.info_outline), onPressed: showInfoSheet), IconButton(icon: Icon(Icons.info_outline), onPressed: showInfoSheet),
@@ -275,3 +298,54 @@ class FileDetailScreen extends HookConsumerWidget {
}; };
} }
} }
class ReferencesList extends ConsumerWidget {
const ReferencesList({super.key, required this.fileId});
final String fileId;
@override
Widget build(BuildContext context, WidgetRef ref) {
final asyncReferences = ref.watch(fileReferencesProvider(fileId));
return asyncReferences.when(
data:
(references) => ListView.builder(
itemCount: references.length,
itemBuilder: (context, index) {
final reference = references[index];
return ListTile(
leading: const Icon(Icons.link),
title: Row(
spacing: 6,
children: [
Text(
reference.usage,
style: GoogleFonts.robotoMono(
fontWeight: FontWeight.bold,
fontSize: 13,
),
),
Text(
reference.id,
style: GoogleFonts.robotoMono(fontSize: 13),
),
],
),
subtitle: Row(
spacing: 8,
children: [
Text(reference.createdAt.formatRelative(context)),
const VerticalDivider(width: 1, thickness: 1).height(12),
Text(reference.createdAt.formatSystem()),
],
),
);
},
),
loading: () => const Center(child: CircularProgressIndicator()),
error:
(error, _) => Center(child: Text('Error loading references: $error')),
);
}
}