1
0
mirror of https://github.com/immich-app/immich.git synced 2024-12-25 10:43:13 +02:00

feat(mobile): use map settings from server-config (#4045)

* feat(mobile): use map settings from server-config to enable / disable map

* refactor(mobile): remove async await for server info update
This commit is contained in:
shenlong 2023-09-28 03:26:48 +00:00 committed by GitHub
parent b7fcec7ce3
commit a937efe719
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 113 additions and 12 deletions

View File

@ -54,7 +54,7 @@ class HomePage extends HookConsumerWidget {
Future(() => ref.read(assetProvider.notifier).getAllAsset());
ref.read(albumProvider.notifier).getAllAlbums();
ref.read(sharedAlbumProvider.notifier).getAllSharedAlbums();
ref.read(serverInfoProvider.notifier).getServerVersion();
ref.read(serverInfoProvider.notifier).getServerInfo();
selectionEnabledHook.addListener(() {
multiselectEnabled.state = selectionEnabledHook.value;

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_map/plugin_api.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
import 'package:immich_mobile/utils/color_filter_generator.dart';
import 'package:latlong2/latlong.dart';
import 'package:url_launcher/url_launcher.dart';
@ -29,8 +30,9 @@ class MapThumbnail extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final tileLayer = TileLayer(
urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: const ['a', 'b', 'c'],
urlTemplate: ref.watch(
serverInfoProvider.select((v) => v.serverConfig.mapTileUrl),
),
);
return SizedBox(

View File

@ -20,6 +20,7 @@ import 'package:immich_mobile/modules/map/ui/map_page_bottom_sheet.dart';
import 'package:immich_mobile/modules/map/ui/map_page_app_bar.dart';
import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/shared/models/asset.dart';
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
import 'package:immich_mobile/shared/ui/immich_toast.dart';
import 'package:immich_mobile/utils/color_filter_generator.dart';
@ -358,8 +359,9 @@ class MapPageState extends ConsumerState<MapPage> {
}
final tileLayer = TileLayer(
urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: const ['a', 'b', 'c'],
urlTemplate: ref.watch(
serverInfoProvider.select((v) => v.serverConfig.mapTileUrl),
),
maxNativeZoom: 19,
maxZoom: 19,
);

View File

@ -8,15 +8,21 @@ import 'package:immich_mobile/shared/models/store.dart';
import 'package:latlong2/latlong.dart';
class CuratedPlacesRow extends CuratedRow {
final bool isMapEnabled;
const CuratedPlacesRow({
super.key,
required super.content,
this.isMapEnabled = true,
super.imageSize,
super.onTap,
});
@override
Widget build(BuildContext context) {
// Calculating the actual index of the content based on the whether map is enabled or not.
// If enabled, inject map as the first item in the list (index 0) and so the actual content will start from index 1
final int actualContentIndex = isMapEnabled ? 1 : 0;
Widget buildMapThumbnail() {
return GestureDetector(
onTap: () => AutoRouter.of(context).push(
@ -75,6 +81,24 @@ class CuratedPlacesRow extends CuratedRow {
);
}
// Return empty thumbnail
if (!isMapEnabled && content.isEmpty) {
return Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: SizedBox(
width: imageSize,
height: imageSize,
child: ThumbnailWithInfo(
textInfo: '',
onTap: () {},
),
),
),
);
}
return ListView.builder(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(
@ -82,11 +106,10 @@ class CuratedPlacesRow extends CuratedRow {
),
itemBuilder: (context, index) {
// Injecting Map thumbnail as the first element
if (index == 0) {
if (isMapEnabled && index == 0) {
return buildMapThumbnail();
}
// The actual index is 1 less than the virutal index since we inject map into the first position
final actualIndex = index - 1;
final actualIndex = index - actualContentIndex;
final object = content[actualIndex];
final thumbnailRequestUrl =
'${Store.get(StoreKey.serverEndpoint)}/asset/thumbnail/${object.id}';
@ -103,8 +126,7 @@ class CuratedPlacesRow extends CuratedRow {
),
);
},
// Adding 1 to inject map thumbnail as first element
itemCount: content.length + 1,
itemCount: content.length + actualContentIndex,
);
}
}

View File

@ -14,6 +14,7 @@ import 'package:immich_mobile/modules/search/ui/person_name_edit_form.dart';
import 'package:immich_mobile/modules/search/ui/search_row_title.dart';
import 'package:immich_mobile/modules/search/ui/search_suggestion_list.dart';
import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
// ignore: must_be_immutable
@ -27,6 +28,8 @@ class SearchPage extends HookConsumerWidget {
final isSearchEnabled = ref.watch(searchPageStateProvider).isSearchEnabled;
final curatedLocation = ref.watch(getCuratedLocationProvider);
final curatedPeople = ref.watch(getCuratedPeopleProvider);
final isMapEnabled =
ref.watch(serverInfoProvider.select((v) => v.serverFeatures.map));
var isDarkTheme = Theme.of(context).brightness == Brightness.dark;
double imageSize = math.min(MediaQuery.of(context).size.width / 3, 150);
@ -107,6 +110,7 @@ class SearchPage extends HookConsumerWidget {
loading: () => const Center(child: ImmichLoadingIndicator()),
error: (err, stack) => Center(child: Text('Error: $err')),
data: (locations) => CuratedPlacesRow(
isMapEnabled: isMapEnabled,
content: locations
.map(
(o) => CuratedContent(

View File

@ -2,22 +2,30 @@ import 'package:openapi/api.dart';
class ServerInfoState {
final ServerVersionResponseDto serverVersion;
final ServerFeaturesDto serverFeatures;
final ServerConfigDto serverConfig;
final bool isVersionMismatch;
final String versionMismatchErrorMessage;
ServerInfoState({
required this.serverVersion,
required this.serverFeatures,
required this.serverConfig,
required this.isVersionMismatch,
required this.versionMismatchErrorMessage,
});
ServerInfoState copyWith({
ServerVersionResponseDto? serverVersion,
ServerFeaturesDto? serverFeatures,
ServerConfigDto? serverConfig,
bool? isVersionMismatch,
String? versionMismatchErrorMessage,
}) {
return ServerInfoState(
serverVersion: serverVersion ?? this.serverVersion,
serverFeatures: serverFeatures ?? this.serverFeatures,
serverConfig: serverConfig ?? this.serverConfig,
isVersionMismatch: isVersionMismatch ?? this.isVersionMismatch,
versionMismatchErrorMessage:
versionMismatchErrorMessage ?? this.versionMismatchErrorMessage,
@ -26,7 +34,7 @@ class ServerInfoState {
@override
String toString() {
return 'ServerInfoState( serverVersion: $serverVersion, isVersionMismatch: $isVersionMismatch, versionMismatchErrorMessage: $versionMismatchErrorMessage)';
return 'ServerInfoState( serverVersion: $serverVersion, serverFeatures: $serverFeatures, serverConfig: $serverConfig, isVersionMismatch: $isVersionMismatch, versionMismatchErrorMessage: $versionMismatchErrorMessage)';
}
@override
@ -35,6 +43,8 @@ class ServerInfoState {
return other is ServerInfoState &&
other.serverVersion == serverVersion &&
other.serverFeatures == serverFeatures &&
other.serverConfig == serverConfig &&
other.isVersionMismatch == isVersionMismatch &&
other.versionMismatchErrorMessage == versionMismatchErrorMessage;
}
@ -42,6 +52,8 @@ class ServerInfoState {
@override
int get hashCode {
return serverVersion.hashCode ^
serverFeatures.hashCode ^
serverConfig.hashCode ^
isVersionMismatch.hashCode ^
versionMismatchErrorMessage.hashCode;
}

View File

@ -15,6 +15,24 @@ class ServerInfoNotifier extends StateNotifier<ServerInfoState> {
patch_: 0,
minor: 0,
),
serverFeatures: ServerFeaturesDto(
clipEncode: true,
configFile: false,
facialRecognition: true,
map: true,
oauth: false,
oauthAutoLaunch: false,
passwordLogin: true,
search: true,
sidecar: true,
tagImage: true,
reverseGeocoding: true,
),
serverConfig: ServerConfigDto(
loginPageMessage: "",
mapTileUrl: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
oauthButtonText: "",
),
isVersionMismatch: false,
versionMismatchErrorMessage: "",
),
@ -22,6 +40,12 @@ class ServerInfoNotifier extends StateNotifier<ServerInfoState> {
final ServerInfoService _serverInfoService;
getServerInfo() {
getServerVersion();
getServerFeatures();
getServerConfig();
}
getServerVersion() async {
ServerVersionResponseDto? serverVersion =
await _serverInfoService.getServerVersion();
@ -66,6 +90,23 @@ class ServerInfoNotifier extends StateNotifier<ServerInfoState> {
);
}
getServerFeatures() async {
ServerFeaturesDto? serverFeatures =
await _serverInfoService.getServerFeatures();
if (serverFeatures == null) {
return;
}
state = state.copyWith(serverFeatures: serverFeatures);
}
getServerConfig() async {
ServerConfigDto? serverConfig = await _serverInfoService.getServerConfig();
if (serverConfig == null) {
return;
}
state = state.copyWith(serverConfig: serverConfig);
}
Map<String, int> _getDetailVersion(String version) {
List<String> detail = version.split(".");

View File

@ -28,7 +28,25 @@ class ServerInfoService {
try {
return await _apiService.serverInfoApi.getServerVersion();
} catch (e) {
debugPrint("Error getting server info");
debugPrint("Error [getServerVersion] ${e.toString()}");
return null;
}
}
Future<ServerFeaturesDto?> getServerFeatures() async {
try {
return await _apiService.serverInfoApi.getServerFeatures();
} catch (e) {
debugPrint("Error [getServerFeatures] ${e.toString()}");
return null;
}
}
Future<ServerConfigDto?> getServerConfig() async {
try {
return await _apiService.serverInfoApi.getServerConfig();
} catch (e) {
debugPrint("Error [getServerConfig] ${e.toString()}");
return null;
}
}