Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/src/app/routing/deep_link.dart
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ Future<void> _initializeLemmyClient(BuildContext context) async {
}

// Validate connection by making a simple request
await InstanceRepositoryImpl(account: account).getSiteInfo();
await InstanceRepositoryImpl(account: account).info();
return;
} catch (e) {
attempts++;
Expand Down
54 changes: 27 additions & 27 deletions lib/src/app/utils/navigation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import 'package:collection/collection.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import 'package:thunder/src/app/routing/swipeable_page_route.dart';
import 'package:thunder/src/app/utils/global_context.dart';
import 'package:thunder/src/core/enums/comment_sort_type.dart';
import 'package:thunder/src/core/enums/threadiverse_platform.dart';
import 'package:thunder/src/core/models/models.dart';
import 'package:thunder/src/core/models/thunder_private_message.dart';
import 'package:thunder/src/core/models/thunder_site_response.dart';
import 'package:thunder/src/features/instance/instance.dart';
import 'package:thunder/l10n/generated/app_localizations.dart';
import 'package:thunder/src/features/account/account.dart';
Expand Down Expand Up @@ -52,38 +54,25 @@ Future<void> navigateToInstancePage(
required String instanceHost,
required int? instanceId,
}) async {
assert(instanceHost.isNotEmpty);

showLoadingPage(context);

final l10n = AppLocalizations.of(context)!;

final profileBloc = context.read<ProfileBloc>();
final thunderBloc = context.read<ThunderBloc>();
final gestureCubit = context.read<GesturePreferencesCubit>();
final themeCubit = context.read<ThemePreferencesCubit>();

final reduceAnimations = themeCubit.state.reduceAnimations;
final enableFullScreenSwipeNavigationGesture = gestureCubit.state.enableFullScreenSwipeNavigationGesture;

ThunderSiteResponse? getSiteResponse;
bool? isBlocked;
final reduceAnimations = context.read<ThemePreferencesCubit>().state.reduceAnimations;
final enableFullScreenSwipeNavigationGesture = context.read<GesturePreferencesCubit>().state.enableFullScreenSwipeNavigationGesture;

final platformInfo = await detectPlatformFromNodeInfo(instanceHost);
final platform = platformInfo?['platform'];
final platform = platformInfo?['platform'] ?? ThreadiversePlatform.lemmy; // Fallback to Lemmy if we can't detect the platform

ThunderSiteResponse? site;

try {
// Get the site information by connecting to the given instance
final account = Account(id: '', index: -1, instance: instanceHost, platform: platform);
getSiteResponse = await InstanceRepositoryImpl(account: account).getSiteInfo().timeout(const Duration(seconds: 5));

// Check whether this instance is blocked (we have to get our user from our current site first).
isBlocked = profileBloc.state.siteResponse?.myUser?.instanceBlocks.any((i) => i.instance['domain'] == instanceHost);
site = await InstanceRepositoryImpl(account: account).info().timeout(const Duration(seconds: 5));
} catch (e) {
// Continue if we can't get the site
}

final SwipeablePageRoute route = SwipeablePageRoute(
final route = SwipeablePageRoute(
transitionDuration: isLoadingPageShown
? Duration.zero
: reduceAnimations
Expand All @@ -93,24 +82,35 @@ Future<void> navigateToInstancePage(
canSwipe: !kIsWeb && Platform.isIOS || enableFullScreenSwipeNavigationGesture,
canOnlySwipeFromEdge: true,
builder: (context) => BlocProvider.value(
value: thunderBloc,
value: context.read<ThunderBloc>(),
child: InstancePage(
platform: platform!,
site: getSiteResponse!,
isBlocked: isBlocked,
instanceId: instanceId,
instance: ThunderInstanceInfo(
id: instanceId,
domain: site!.site.actorId,
name: site.site.name,
description: site.site.description,
sidebar: site.site.sidebar,
icon: site.site.icon,
users: site.site.users,
version: site.version,
platform: platform,
contentWarning: site.site.contentWarning,
),
),
),
);

if (getSiteResponse != null) {
if (site != null) {
pushOnTopOfLoadingPage(context, route);
} else {
final l10n = GlobalContext.l10n;

showSnackbar(
l10n.unableToNavigateToInstance(instanceHost),
trailingAction: () => handleLink(context, url: "https://$instanceHost", forceOpenInBrowser: true),
trailingIcon: Icons.open_in_browser_rounded,
);

hideLoadingPage(context);
}
}
Expand Down
6 changes: 6 additions & 0 deletions lib/src/core/enums/threadiverse_platform.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ enum ThreadiversePlatform {
}
}

/// The name of the platform, formatted for display
String get displayName => switch (this) {
ThreadiversePlatform.lemmy => 'Lemmy',
ThreadiversePlatform.piefed => 'PieFed',
};

/// Converts ThreadiversePlatform enum to string
String? toStringValue() => name;
}
33 changes: 21 additions & 12 deletions lib/src/core/models/thunder_instance_info.dart
Original file line number Diff line number Diff line change
@@ -1,44 +1,53 @@
import 'package:thunder/src/core/enums/threadiverse_platform.dart';

/// A class that holds metadata about an instance.
class ThunderInstanceInfo {
const ThunderInstanceInfo({
this.id,
this.domain,
required this.domain,
this.version,
this.name,
required this.name,
this.description,
this.sidebar,
this.icon,
this.users,
this.success = false,
this.platform,
this.contentWarning,
});

bool isMetadataPopulated() => icon != null || version != null || name != null || users != null;
bool isMetadataPopulated() => icon != null || version != null || users != null;

/// The ID of the instance.
final int? id;

/// The domain of the instance.
final String? domain;
final String domain;

/// The Lemmy version of the instance.
/// The platform of the instance.
final ThreadiversePlatform? platform;

/// The version of the instance.
final String? version;

/// The name of the instance.
final String? name;
final String name;

/// The icon of the instance.
final String? icon;

/// The description of the instance.
final String? description;

/// The sidebar of the instance.
final String? sidebar;

/// The content warning of the instance.
final String? contentWarning;

/// The number of users on the instance.
final int? users;

/// Whether the instance was successfully fetched.
final bool success;

/// The platform of the instance.
final ThreadiversePlatform? platform;

/// The content warning of the instance.
final String? contentWarning;
}
2 changes: 1 addition & 1 deletion lib/src/core/network/lemmy_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ class LemmyApi {
'community': json['community'] != null ? ThunderCommunity.fromLemmyCommunityView(json['community']) : null,
'post': json['post'] != null ? ThunderPost.fromLemmyPostView(json['post']) : null,
'comment': json['comment'] != null ? ThunderComment.fromLemmyCommentView(json['comment']) : null,
'user': json['user'] != null ? ThunderUser.fromLemmyUserView(json['user']) : null,
'user': json['person'] != null ? ThunderUser.fromLemmyUserView(json['person']) : null,
};
}

Expand Down
6 changes: 3 additions & 3 deletions lib/src/features/account/presentation/bloc/profile_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
ThunderSiteResponse? siteResponse;

try {
siteResponse = await instanceRepository!.getSiteInfo().timeout(const Duration(seconds: 15));
siteResponse = await instanceRepository!.info().timeout(const Duration(seconds: 15));
downvotesEnabled = siteResponse.site.enableDownvotes ?? true;
} catch (e) {
return emit(state.copyWith(status: ProfileStatus.failureCheckingInstance, error: () => getExceptionErrorMessage(e)));
Expand Down Expand Up @@ -134,7 +134,7 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {

// Create a temporary instance repository to use for the site information
tempAccount = Account(id: '', index: -1, jwt: jwt, instance: tempAccount.instance, platform: platform);
final siteResponse = await InstanceRepositoryImpl(account: tempAccount).getSiteInfo();
final siteResponse = await InstanceRepositoryImpl(account: tempAccount).info();

if (event.showContentWarning && siteResponse.site.contentWarning?.isNotEmpty == true) {
return emit(state.copyWith(status: ProfileStatus.contentWarning, contentWarning: () => siteResponse.site.contentWarning!));
Expand Down Expand Up @@ -252,7 +252,7 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
emit(state.copyWith(status: ProfileStatus.loading));

// Refresh the site information, which includes the user's settings
final response = await instanceRepository!.getSiteInfo();
final response = await instanceRepository!.info();

return emit(state.copyWith(status: ProfileStatus.success, siteResponse: () => response));
} catch (e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,11 @@ class _ProfileSelectState extends State<ProfileSelect> {
for (final account in accountsExtended) {
final instanceInfo = await getInstanceInfo(account.instance).timeout(
const Duration(seconds: 5),
onTimeout: () => const ThunderInstanceInfo(success: false),
onTimeout: () => ThunderInstanceInfo(
domain: account.instance!,
name: fetchInstanceNameFromUrl(account.instance!)!,
success: false,
),
);

if (mounted) {
Expand Down Expand Up @@ -802,7 +806,11 @@ class _ProfileSelectState extends State<ProfileSelect> {
for (final anonymousInstanceExtended in anonymousInstancesExtended) {
final instanceInfo = await getInstanceInfo(anonymousInstanceExtended.anonymousInstance.instance).timeout(
const Duration(seconds: 5),
onTimeout: () => const ThunderInstanceInfo(success: false),
onTimeout: () => ThunderInstanceInfo(
domain: anonymousInstanceExtended.anonymousInstance.instance,
name: fetchInstanceNameFromUrl(anonymousInstanceExtended.anonymousInstance.instance)!,
success: false,
),
);

if (mounted) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ class CommunityListEntry extends StatefulWidget {
/// Whether to indicate that the community is a favorite.
final bool indicateFavorites;

/// Whether the community should be resolved to a different instance
final String? resolutionInstance;
/// The account to use for resolving the community to a different instance
final Account? resolutionAccount;

const CommunityListEntry({
super.key,
required this.community,
this.indicateFavorites = true,
this.resolutionInstance,
this.resolutionAccount,
});

@override
Expand Down Expand Up @@ -120,7 +120,7 @@ class _CommunityListEntryState extends State<CommunityListEntry> {
]
],
),
trailing: widget.resolutionInstance == null
trailing: widget.resolutionAccount == null
? IconButton(
onPressed: () {
onSubscribe(community.subscribed != SubscriptionStatus.notSubscribed, isUserLoggedIn);
Expand All @@ -144,11 +144,9 @@ class _CommunityListEntryState extends State<CommunityListEntry> {
onTap: () async {
int? communityId = widget.community.id;

if (widget.resolutionInstance != null) {
if (widget.resolutionAccount != null) {
try {
// Create a temporary Account
final account = Account(instance: widget.resolutionInstance!, id: '', index: -1);
final response = await SearchRepositoryImpl(account: account).resolve(query: widget.community.actorId);
final response = await SearchRepositoryImpl(account: widget.resolutionAccount!).resolve(query: widget.community.actorId);

communityId = response['community']?.id;
} catch (e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import 'package:thunder/src/app/utils/global_context.dart';
/// Interface for a instance repository
abstract class InstanceRepository {
/// Fetches the site info
Future<ThunderSiteResponse> getSiteInfo();
Future<ThunderSiteResponse> info();

/// Blocks a given instance
Future<bool> block(int instanceId, bool block);
Expand Down Expand Up @@ -49,7 +49,7 @@ class InstanceRepositoryImpl implements InstanceRepository {
}

@override
Future<ThunderSiteResponse> getSiteInfo() async {
Future<ThunderSiteResponse> info() async {
switch (account.platform) {
case ThreadiversePlatform.lemmy:
return await client.site();
Expand Down
12 changes: 0 additions & 12 deletions lib/src/features/instance/domain/enums/instance_action.dart

This file was deleted.

4 changes: 1 addition & 3 deletions lib/src/features/instance/instance.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
export 'domain/enums/instance_action.dart';
export 'data/repositories/instance_repository.dart';
export 'presentation/bloc/instance_page_cubit.dart';
export 'presentation/pages/instance_page.dart';
export 'presentation/widgets/instance_view.dart';
export 'presentation/widgets/instance_information.dart';
export 'presentation/widgets/instance_list_entry.dart';
export 'presentation/widgets/instance_action_bottom_sheet.dart';
Loading