kopia lustrzana https://gitlab.com/mysocialportal/relatica
Initial implementation of the a user's media screen
rodzic
9913161a3a
commit
5e1a164d06
|
@ -6,6 +6,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import '../../globals.dart';
|
import '../../globals.dart';
|
||||||
import '../../models/auth/profile.dart';
|
import '../../models/auth/profile.dart';
|
||||||
import '../../models/exec_error.dart';
|
import '../../models/exec_error.dart';
|
||||||
|
import '../../models/networking/paged_response.dart';
|
||||||
import '../../models/networking/paging_data.dart';
|
import '../../models/networking/paging_data.dart';
|
||||||
import '../../models/timeline_entry.dart';
|
import '../../models/timeline_entry.dart';
|
||||||
import '../../models/timeline_identifiers.dart';
|
import '../../models/timeline_identifiers.dart';
|
||||||
|
@ -47,6 +48,40 @@ Future<Result<List<TimelineEntry>, ExecError>> timeline(
|
||||||
return result.execErrorCast();
|
return result.execErrorCast();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<Result<PagedResponse<List<TimelineEntry>>, ExecError>>
|
||||||
|
userMediaTimelineClient(
|
||||||
|
Ref ref,
|
||||||
|
Profile profile,
|
||||||
|
String accountId, {
|
||||||
|
required PagingData page,
|
||||||
|
}) async {
|
||||||
|
final type =
|
||||||
|
TimelineIdentifiers(timeline: TimelineType.profile, auxData: accountId);
|
||||||
|
ref.read(timelineLoadingStatusProvider(profile, type));
|
||||||
|
Future.microtask(
|
||||||
|
() async =>
|
||||||
|
ref.read(timelineLoadingStatusProvider(profile, type).notifier).begin(),
|
||||||
|
);
|
||||||
|
|
||||||
|
final String timelineQPs = _typeToTimelineQueryParameters(type);
|
||||||
|
final baseUrl =
|
||||||
|
'https://${profile.serverName}/api/v1/accounts/$accountId/statuses';
|
||||||
|
final url =
|
||||||
|
'$baseUrl?only_media=true&${page.toQueryParameters()}&$timelineQPs';
|
||||||
|
final request = Uri.parse(url);
|
||||||
|
_logger.info(
|
||||||
|
() => 'Getting ${type.toHumanKey()} media only with paging data $page');
|
||||||
|
final result = await ref
|
||||||
|
.read(getApiListRequestProvider(profile, request).future)
|
||||||
|
.transformAsync((response) async {
|
||||||
|
final entries = await _timelineEntriesFromJson(ref, profile, response.data);
|
||||||
|
return response.map((_) => entries);
|
||||||
|
});
|
||||||
|
ref.read(timelineLoadingStatusProvider(profile, type).notifier).end();
|
||||||
|
return result.execErrorCast();
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<TimelineEntry>> _timelineEntriesFromJson(
|
Future<List<TimelineEntry>> _timelineEntriesFromJson(
|
||||||
Ref ref,
|
Ref ref,
|
||||||
Profile profile,
|
Profile profile,
|
||||||
|
|
|
@ -194,5 +194,177 @@ class _TimelineProviderElement extends AutoDisposeFutureProviderElement<
|
||||||
@override
|
@override
|
||||||
PagingData get page => (origin as TimelineProvider).page;
|
PagingData get page => (origin as TimelineProvider).page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _$userMediaTimelineClientHash() =>
|
||||||
|
r'e4a21707ca98374e69ad289412f8accea32e367d';
|
||||||
|
|
||||||
|
/// See also [userMediaTimelineClient].
|
||||||
|
@ProviderFor(userMediaTimelineClient)
|
||||||
|
const userMediaTimelineClientProvider = UserMediaTimelineClientFamily();
|
||||||
|
|
||||||
|
/// See also [userMediaTimelineClient].
|
||||||
|
class UserMediaTimelineClientFamily extends Family<
|
||||||
|
AsyncValue<Result<PagedResponse<List<TimelineEntry>>, ExecError>>> {
|
||||||
|
/// See also [userMediaTimelineClient].
|
||||||
|
const UserMediaTimelineClientFamily();
|
||||||
|
|
||||||
|
/// See also [userMediaTimelineClient].
|
||||||
|
UserMediaTimelineClientProvider call(
|
||||||
|
Profile profile,
|
||||||
|
String accountId, {
|
||||||
|
required PagingData page,
|
||||||
|
}) {
|
||||||
|
return UserMediaTimelineClientProvider(
|
||||||
|
profile,
|
||||||
|
accountId,
|
||||||
|
page: page,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
UserMediaTimelineClientProvider getProviderOverride(
|
||||||
|
covariant UserMediaTimelineClientProvider provider,
|
||||||
|
) {
|
||||||
|
return call(
|
||||||
|
provider.profile,
|
||||||
|
provider.accountId,
|
||||||
|
page: provider.page,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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'userMediaTimelineClientProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [userMediaTimelineClient].
|
||||||
|
class UserMediaTimelineClientProvider extends AutoDisposeFutureProvider<
|
||||||
|
Result<PagedResponse<List<TimelineEntry>>, ExecError>> {
|
||||||
|
/// See also [userMediaTimelineClient].
|
||||||
|
UserMediaTimelineClientProvider(
|
||||||
|
Profile profile,
|
||||||
|
String accountId, {
|
||||||
|
required PagingData page,
|
||||||
|
}) : this._internal(
|
||||||
|
(ref) => userMediaTimelineClient(
|
||||||
|
ref as UserMediaTimelineClientRef,
|
||||||
|
profile,
|
||||||
|
accountId,
|
||||||
|
page: page,
|
||||||
|
),
|
||||||
|
from: userMediaTimelineClientProvider,
|
||||||
|
name: r'userMediaTimelineClientProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$userMediaTimelineClientHash,
|
||||||
|
dependencies: UserMediaTimelineClientFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
UserMediaTimelineClientFamily._allTransitiveDependencies,
|
||||||
|
profile: profile,
|
||||||
|
accountId: accountId,
|
||||||
|
page: page,
|
||||||
|
);
|
||||||
|
|
||||||
|
UserMediaTimelineClientProvider._internal(
|
||||||
|
super._createNotifier, {
|
||||||
|
required super.name,
|
||||||
|
required super.dependencies,
|
||||||
|
required super.allTransitiveDependencies,
|
||||||
|
required super.debugGetCreateSourceHash,
|
||||||
|
required super.from,
|
||||||
|
required this.profile,
|
||||||
|
required this.accountId,
|
||||||
|
required this.page,
|
||||||
|
}) : super.internal();
|
||||||
|
|
||||||
|
final Profile profile;
|
||||||
|
final String accountId;
|
||||||
|
final PagingData page;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Override overrideWith(
|
||||||
|
FutureOr<Result<PagedResponse<List<TimelineEntry>>, ExecError>> Function(
|
||||||
|
UserMediaTimelineClientRef provider)
|
||||||
|
create,
|
||||||
|
) {
|
||||||
|
return ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
override: UserMediaTimelineClientProvider._internal(
|
||||||
|
(ref) => create(ref as UserMediaTimelineClientRef),
|
||||||
|
from: from,
|
||||||
|
name: null,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
debugGetCreateSourceHash: null,
|
||||||
|
profile: profile,
|
||||||
|
accountId: accountId,
|
||||||
|
page: page,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AutoDisposeFutureProviderElement<
|
||||||
|
Result<PagedResponse<List<TimelineEntry>>, ExecError>> createElement() {
|
||||||
|
return _UserMediaTimelineClientProviderElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is UserMediaTimelineClientProvider &&
|
||||||
|
other.profile == profile &&
|
||||||
|
other.accountId == accountId &&
|
||||||
|
other.page == page;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, profile.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, accountId.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, page.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
|
mixin UserMediaTimelineClientRef on AutoDisposeFutureProviderRef<
|
||||||
|
Result<PagedResponse<List<TimelineEntry>>, ExecError>> {
|
||||||
|
/// The parameter `profile` of this provider.
|
||||||
|
Profile get profile;
|
||||||
|
|
||||||
|
/// The parameter `accountId` of this provider.
|
||||||
|
String get accountId;
|
||||||
|
|
||||||
|
/// The parameter `page` of this provider.
|
||||||
|
PagingData get page;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _UserMediaTimelineClientProviderElement
|
||||||
|
extends AutoDisposeFutureProviderElement<
|
||||||
|
Result<PagedResponse<List<TimelineEntry>>, ExecError>>
|
||||||
|
with UserMediaTimelineClientRef {
|
||||||
|
_UserMediaTimelineClientProviderElement(super.provider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Profile get profile => (origin as UserMediaTimelineClientProvider).profile;
|
||||||
|
@override
|
||||||
|
String get accountId => (origin as UserMediaTimelineClientProvider).accountId;
|
||||||
|
@override
|
||||||
|
PagingData get page => (origin as UserMediaTimelineClientProvider).page;
|
||||||
|
}
|
||||||
// ignore_for_file: type=lint
|
// 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
|
// 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
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:result_monad/result_monad.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:stack_trace/stack_trace.dart';
|
import 'package:stack_trace/stack_trace.dart';
|
||||||
|
|
||||||
import '../models/auth/profile.dart';
|
import '../models/auth/profile.dart';
|
||||||
|
import '../models/exec_error.dart';
|
||||||
|
import '../models/media_attachment.dart';
|
||||||
|
import '../models/networking/paging_data.dart';
|
||||||
import '../models/timeline.dart';
|
import '../models/timeline.dart';
|
||||||
import '../models/timeline_identifiers.dart';
|
import '../models/timeline_identifiers.dart';
|
||||||
|
import '../riverpod_controllers/networking/friendica_timelines_client_services.dart';
|
||||||
import 'entry_tree_item_services.dart';
|
import 'entry_tree_item_services.dart';
|
||||||
|
|
||||||
part 'timeline_services.g.dart';
|
part 'timeline_services.g.dart';
|
||||||
|
@ -147,3 +152,41 @@ class TimelineManager extends _$TimelineManager {
|
||||||
return hadItem;
|
return hadItem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
class UserMediaTimeline extends _$UserMediaTimeline {
|
||||||
|
static const limit = 50;
|
||||||
|
var nextPage = const PagingData(limit: limit);
|
||||||
|
var media = <MediaAttachment>[];
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Result<List<MediaAttachment>, ExecError>> build(
|
||||||
|
Profile profile, String accountId) async {
|
||||||
|
await updateTimeline(reset: true, withNotification: false);
|
||||||
|
return Result.ok(media);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Result<List<MediaAttachment>, ExecError>> updateTimeline(
|
||||||
|
{bool reset = true, bool withNotification = true}) async {
|
||||||
|
if (reset) {
|
||||||
|
nextPage = const PagingData(limit: limit);
|
||||||
|
media.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
final result = await ref.watch(
|
||||||
|
userMediaTimelineClientProvider(profile, accountId, page: nextPage)
|
||||||
|
.future);
|
||||||
|
return result
|
||||||
|
.withResult((result) {
|
||||||
|
for (final entries in result.data) {
|
||||||
|
media.addAll(entries.mediaAttachments);
|
||||||
|
}
|
||||||
|
nextPage = result.next!;
|
||||||
|
if (withNotification) {
|
||||||
|
ref.notifyListeners();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.transform((_) => media)
|
||||||
|
.execErrorCast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -340,5 +340,176 @@ class _TimelineManagerProviderElement
|
||||||
TimelineIdentifiers get timelineId =>
|
TimelineIdentifiers get timelineId =>
|
||||||
(origin as TimelineManagerProvider).timelineId;
|
(origin as TimelineManagerProvider).timelineId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _$userMediaTimelineHash() => r'f13ba417b1d5550392f973af9e86c099efd60491';
|
||||||
|
|
||||||
|
abstract class _$UserMediaTimeline extends BuildlessAutoDisposeAsyncNotifier<
|
||||||
|
Result<List<MediaAttachment>, ExecError>> {
|
||||||
|
late final Profile profile;
|
||||||
|
late final String accountId;
|
||||||
|
|
||||||
|
FutureOr<Result<List<MediaAttachment>, ExecError>> build(
|
||||||
|
Profile profile,
|
||||||
|
String accountId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [UserMediaTimeline].
|
||||||
|
@ProviderFor(UserMediaTimeline)
|
||||||
|
const userMediaTimelineProvider = UserMediaTimelineFamily();
|
||||||
|
|
||||||
|
/// See also [UserMediaTimeline].
|
||||||
|
class UserMediaTimelineFamily
|
||||||
|
extends Family<AsyncValue<Result<List<MediaAttachment>, ExecError>>> {
|
||||||
|
/// See also [UserMediaTimeline].
|
||||||
|
const UserMediaTimelineFamily();
|
||||||
|
|
||||||
|
/// See also [UserMediaTimeline].
|
||||||
|
UserMediaTimelineProvider call(
|
||||||
|
Profile profile,
|
||||||
|
String accountId,
|
||||||
|
) {
|
||||||
|
return UserMediaTimelineProvider(
|
||||||
|
profile,
|
||||||
|
accountId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
UserMediaTimelineProvider getProviderOverride(
|
||||||
|
covariant UserMediaTimelineProvider provider,
|
||||||
|
) {
|
||||||
|
return call(
|
||||||
|
provider.profile,
|
||||||
|
provider.accountId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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'userMediaTimelineProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [UserMediaTimeline].
|
||||||
|
class UserMediaTimelineProvider extends AutoDisposeAsyncNotifierProviderImpl<
|
||||||
|
UserMediaTimeline, Result<List<MediaAttachment>, ExecError>> {
|
||||||
|
/// See also [UserMediaTimeline].
|
||||||
|
UserMediaTimelineProvider(
|
||||||
|
Profile profile,
|
||||||
|
String accountId,
|
||||||
|
) : this._internal(
|
||||||
|
() => UserMediaTimeline()
|
||||||
|
..profile = profile
|
||||||
|
..accountId = accountId,
|
||||||
|
from: userMediaTimelineProvider,
|
||||||
|
name: r'userMediaTimelineProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$userMediaTimelineHash,
|
||||||
|
dependencies: UserMediaTimelineFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
UserMediaTimelineFamily._allTransitiveDependencies,
|
||||||
|
profile: profile,
|
||||||
|
accountId: accountId,
|
||||||
|
);
|
||||||
|
|
||||||
|
UserMediaTimelineProvider._internal(
|
||||||
|
super._createNotifier, {
|
||||||
|
required super.name,
|
||||||
|
required super.dependencies,
|
||||||
|
required super.allTransitiveDependencies,
|
||||||
|
required super.debugGetCreateSourceHash,
|
||||||
|
required super.from,
|
||||||
|
required this.profile,
|
||||||
|
required this.accountId,
|
||||||
|
}) : super.internal();
|
||||||
|
|
||||||
|
final Profile profile;
|
||||||
|
final String accountId;
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<Result<List<MediaAttachment>, ExecError>> runNotifierBuild(
|
||||||
|
covariant UserMediaTimeline notifier,
|
||||||
|
) {
|
||||||
|
return notifier.build(
|
||||||
|
profile,
|
||||||
|
accountId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Override overrideWith(UserMediaTimeline Function() create) {
|
||||||
|
return ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
override: UserMediaTimelineProvider._internal(
|
||||||
|
() => create()
|
||||||
|
..profile = profile
|
||||||
|
..accountId = accountId,
|
||||||
|
from: from,
|
||||||
|
name: null,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
debugGetCreateSourceHash: null,
|
||||||
|
profile: profile,
|
||||||
|
accountId: accountId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AutoDisposeAsyncNotifierProviderElement<UserMediaTimeline,
|
||||||
|
Result<List<MediaAttachment>, ExecError>> createElement() {
|
||||||
|
return _UserMediaTimelineProviderElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is UserMediaTimelineProvider &&
|
||||||
|
other.profile == profile &&
|
||||||
|
other.accountId == accountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, profile.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, accountId.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
|
// ignore: unused_element
|
||||||
|
mixin UserMediaTimelineRef on AutoDisposeAsyncNotifierProviderRef<
|
||||||
|
Result<List<MediaAttachment>, ExecError>> {
|
||||||
|
/// The parameter `profile` of this provider.
|
||||||
|
Profile get profile;
|
||||||
|
|
||||||
|
/// The parameter `accountId` of this provider.
|
||||||
|
String get accountId;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _UserMediaTimelineProviderElement
|
||||||
|
extends AutoDisposeAsyncNotifierProviderElement<UserMediaTimeline,
|
||||||
|
Result<List<MediaAttachment>, ExecError>> with UserMediaTimelineRef {
|
||||||
|
_UserMediaTimelineProviderElement(super.provider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Profile get profile => (origin as UserMediaTimelineProvider).profile;
|
||||||
|
@override
|
||||||
|
String get accountId => (origin as UserMediaTimelineProvider).accountId;
|
||||||
|
}
|
||||||
// ignore_for_file: type=lint
|
// 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
|
// 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
|
||||||
|
|
|
@ -28,6 +28,7 @@ import 'screens/settings_screen.dart';
|
||||||
import 'screens/sign_in.dart';
|
import 'screens/sign_in.dart';
|
||||||
import 'screens/splash.dart';
|
import 'screens/splash.dart';
|
||||||
import 'screens/tags_timeline_screen.dart';
|
import 'screens/tags_timeline_screen.dart';
|
||||||
|
import 'screens/user_media_screen.dart';
|
||||||
import 'screens/user_posts_screen.dart';
|
import 'screens/user_posts_screen.dart';
|
||||||
import 'screens/user_profile_screen.dart';
|
import 'screens/user_profile_screen.dart';
|
||||||
|
|
||||||
|
@ -50,6 +51,7 @@ class ScreenPaths {
|
||||||
static String signup = '/signup';
|
static String signup = '/signup';
|
||||||
static String userProfile = '/user_profile';
|
static String userProfile = '/user_profile';
|
||||||
static String userPosts = '/user_posts';
|
static String userPosts = '/user_posts';
|
||||||
|
static String userMedia = '/user_media';
|
||||||
static String likes = '/likes';
|
static String likes = '/likes';
|
||||||
static String reshares = '/reshares';
|
static String reshares = '/reshares';
|
||||||
static String explore = '/explore';
|
static String explore = '/explore';
|
||||||
|
@ -271,6 +273,12 @@ final routes = [
|
||||||
builder: (context, state) =>
|
builder: (context, state) =>
|
||||||
UserPostsScreen(userId: state.pathParameters['id']!),
|
UserPostsScreen(userId: state.pathParameters['id']!),
|
||||||
),
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/user_media/:id',
|
||||||
|
name: ScreenPaths.userMedia,
|
||||||
|
builder: (context, state) =>
|
||||||
|
UserMediaScreen(userId: state.pathParameters['id']!),
|
||||||
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/likes/:id',
|
path: '/likes/:id',
|
||||||
name: ScreenPaths.likes,
|
name: ScreenPaths.likes,
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
|
import '../controls/async_value_widget.dart';
|
||||||
|
import '../controls/error_message_widget.dart';
|
||||||
|
import '../controls/media_attachment_viewer_control.dart';
|
||||||
|
import '../controls/standard_appbar.dart';
|
||||||
|
import '../models/timeline_identifiers.dart';
|
||||||
|
import '../riverpod_controllers/account_services.dart';
|
||||||
|
import '../riverpod_controllers/networking/network_status_services.dart';
|
||||||
|
import '../riverpod_controllers/timeline_services.dart';
|
||||||
|
|
||||||
|
class UserMediaScreen extends ConsumerStatefulWidget {
|
||||||
|
final String userId;
|
||||||
|
|
||||||
|
const UserMediaScreen({super.key, required this.userId});
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<UserMediaScreen> createState() => _UserMediaScreenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _UserMediaScreenState extends ConsumerState<UserMediaScreen> {
|
||||||
|
static const thumbnailDimension = 350.0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final profile = ref.watch(activeProfileProvider);
|
||||||
|
final timeline = TimelineIdentifiers.profile(widget.userId);
|
||||||
|
final loading = ref.watch(timelineLoadingStatusProvider(profile, timeline));
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: StandardAppBar.build(
|
||||||
|
context,
|
||||||
|
'User Posts',
|
||||||
|
actions: [],
|
||||||
|
),
|
||||||
|
body: Center(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
if (loading) const LinearProgressIndicator(),
|
||||||
|
Expanded(
|
||||||
|
child: AsyncValueWidget(
|
||||||
|
ref.watch(userMediaTimelineProvider(profile, widget.userId)),
|
||||||
|
valueBuilder: (_, __, result) {
|
||||||
|
return result.fold(
|
||||||
|
onSuccess: (media) {
|
||||||
|
if (media.isEmpty) {
|
||||||
|
return const ErrorMessageWidget(
|
||||||
|
message: 'No media for this user');
|
||||||
|
}
|
||||||
|
|
||||||
|
return GridView.builder(
|
||||||
|
itemCount: media.length,
|
||||||
|
padding: const EdgeInsets.all(5.0),
|
||||||
|
gridDelegate:
|
||||||
|
const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||||
|
maxCrossAxisExtent: thumbnailDimension),
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
if (index == media.length - 1) {
|
||||||
|
ref
|
||||||
|
.read(userMediaTimelineProvider(
|
||||||
|
profile, widget.userId)
|
||||||
|
.notifier)
|
||||||
|
.updateTimeline(
|
||||||
|
reset: false,
|
||||||
|
withNotification: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(2.0),
|
||||||
|
child: MediaAttachmentViewerControl(
|
||||||
|
attachments: [media[index]], index: 0),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onError: (error) =>
|
||||||
|
ErrorMessageWidget(message: error.message));
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -85,7 +85,15 @@ class _UserProfileScreenState extends ConsumerState<UserProfileScreen> {
|
||||||
ScreenPaths.userPosts,
|
ScreenPaths.userPosts,
|
||||||
pathParameters: {'id': connectionProfile.id},
|
pathParameters: {'id': connectionProfile.id},
|
||||||
),
|
),
|
||||||
child: const Text('Posts')),
|
child: const Text('Posts'),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () => context.pushNamed(
|
||||||
|
ScreenPaths.userMedia,
|
||||||
|
pathParameters: {'id': connectionProfile.id},
|
||||||
|
),
|
||||||
|
child: const Text('Media'),
|
||||||
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () async =>
|
onPressed: () async =>
|
||||||
await openProfileExternal(context, connectionProfile),
|
await openProfileExternal(context, connectionProfile),
|
||||||
|
|
Ładowanie…
Reference in New Issue