mirror of
https://github.com/immich-app/immich.git
synced 2024-11-28 09:33:27 +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:
parent
b7fcec7ce3
commit
a937efe719
@ -54,7 +54,7 @@ class HomePage extends HookConsumerWidget {
|
|||||||
Future(() => ref.read(assetProvider.notifier).getAllAsset());
|
Future(() => ref.read(assetProvider.notifier).getAllAsset());
|
||||||
ref.read(albumProvider.notifier).getAllAlbums();
|
ref.read(albumProvider.notifier).getAllAlbums();
|
||||||
ref.read(sharedAlbumProvider.notifier).getAllSharedAlbums();
|
ref.read(sharedAlbumProvider.notifier).getAllSharedAlbums();
|
||||||
ref.read(serverInfoProvider.notifier).getServerVersion();
|
ref.read(serverInfoProvider.notifier).getServerInfo();
|
||||||
|
|
||||||
selectionEnabledHook.addListener(() {
|
selectionEnabledHook.addListener(() {
|
||||||
multiselectEnabled.state = selectionEnabledHook.value;
|
multiselectEnabled.state = selectionEnabledHook.value;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_map/plugin_api.dart';
|
import 'package:flutter_map/plugin_api.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.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:immich_mobile/utils/color_filter_generator.dart';
|
||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
@ -29,8 +30,9 @@ class MapThumbnail extends HookConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final tileLayer = TileLayer(
|
final tileLayer = TileLayer(
|
||||||
urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
urlTemplate: ref.watch(
|
||||||
subdomains: const ['a', 'b', 'c'],
|
serverInfoProvider.select((v) => v.serverConfig.mapTileUrl),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
|
@ -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/modules/map/ui/map_page_app_bar.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
import 'package:immich_mobile/shared/models/asset.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_loading_indicator.dart';
|
||||||
import 'package:immich_mobile/shared/ui/immich_toast.dart';
|
import 'package:immich_mobile/shared/ui/immich_toast.dart';
|
||||||
import 'package:immich_mobile/utils/color_filter_generator.dart';
|
import 'package:immich_mobile/utils/color_filter_generator.dart';
|
||||||
@ -358,8 +359,9 @@ class MapPageState extends ConsumerState<MapPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final tileLayer = TileLayer(
|
final tileLayer = TileLayer(
|
||||||
urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
urlTemplate: ref.watch(
|
||||||
subdomains: const ['a', 'b', 'c'],
|
serverInfoProvider.select((v) => v.serverConfig.mapTileUrl),
|
||||||
|
),
|
||||||
maxNativeZoom: 19,
|
maxNativeZoom: 19,
|
||||||
maxZoom: 19,
|
maxZoom: 19,
|
||||||
);
|
);
|
||||||
|
@ -8,15 +8,21 @@ import 'package:immich_mobile/shared/models/store.dart';
|
|||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
|
|
||||||
class CuratedPlacesRow extends CuratedRow {
|
class CuratedPlacesRow extends CuratedRow {
|
||||||
|
final bool isMapEnabled;
|
||||||
|
|
||||||
const CuratedPlacesRow({
|
const CuratedPlacesRow({
|
||||||
super.key,
|
super.key,
|
||||||
required super.content,
|
required super.content,
|
||||||
|
this.isMapEnabled = true,
|
||||||
super.imageSize,
|
super.imageSize,
|
||||||
super.onTap,
|
super.onTap,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
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() {
|
Widget buildMapThumbnail() {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () => AutoRouter.of(context).push(
|
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(
|
return ListView.builder(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
@ -82,11 +106,10 @@ class CuratedPlacesRow extends CuratedRow {
|
|||||||
),
|
),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
// Injecting Map thumbnail as the first element
|
// Injecting Map thumbnail as the first element
|
||||||
if (index == 0) {
|
if (isMapEnabled && index == 0) {
|
||||||
return buildMapThumbnail();
|
return buildMapThumbnail();
|
||||||
}
|
}
|
||||||
// The actual index is 1 less than the virutal index since we inject map into the first position
|
final actualIndex = index - actualContentIndex;
|
||||||
final actualIndex = index - 1;
|
|
||||||
final object = content[actualIndex];
|
final object = content[actualIndex];
|
||||||
final thumbnailRequestUrl =
|
final thumbnailRequestUrl =
|
||||||
'${Store.get(StoreKey.serverEndpoint)}/asset/thumbnail/${object.id}';
|
'${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 + actualContentIndex,
|
||||||
itemCount: content.length + 1,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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_row_title.dart';
|
||||||
import 'package:immich_mobile/modules/search/ui/search_suggestion_list.dart';
|
import 'package:immich_mobile/modules/search/ui/search_suggestion_list.dart';
|
||||||
import 'package:immich_mobile/routing/router.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';
|
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
|
||||||
|
|
||||||
// ignore: must_be_immutable
|
// ignore: must_be_immutable
|
||||||
@ -27,6 +28,8 @@ class SearchPage extends HookConsumerWidget {
|
|||||||
final isSearchEnabled = ref.watch(searchPageStateProvider).isSearchEnabled;
|
final isSearchEnabled = ref.watch(searchPageStateProvider).isSearchEnabled;
|
||||||
final curatedLocation = ref.watch(getCuratedLocationProvider);
|
final curatedLocation = ref.watch(getCuratedLocationProvider);
|
||||||
final curatedPeople = ref.watch(getCuratedPeopleProvider);
|
final curatedPeople = ref.watch(getCuratedPeopleProvider);
|
||||||
|
final isMapEnabled =
|
||||||
|
ref.watch(serverInfoProvider.select((v) => v.serverFeatures.map));
|
||||||
var isDarkTheme = Theme.of(context).brightness == Brightness.dark;
|
var isDarkTheme = Theme.of(context).brightness == Brightness.dark;
|
||||||
double imageSize = math.min(MediaQuery.of(context).size.width / 3, 150);
|
double imageSize = math.min(MediaQuery.of(context).size.width / 3, 150);
|
||||||
|
|
||||||
@ -107,6 +110,7 @@ class SearchPage extends HookConsumerWidget {
|
|||||||
loading: () => const Center(child: ImmichLoadingIndicator()),
|
loading: () => const Center(child: ImmichLoadingIndicator()),
|
||||||
error: (err, stack) => Center(child: Text('Error: $err')),
|
error: (err, stack) => Center(child: Text('Error: $err')),
|
||||||
data: (locations) => CuratedPlacesRow(
|
data: (locations) => CuratedPlacesRow(
|
||||||
|
isMapEnabled: isMapEnabled,
|
||||||
content: locations
|
content: locations
|
||||||
.map(
|
.map(
|
||||||
(o) => CuratedContent(
|
(o) => CuratedContent(
|
||||||
|
@ -2,22 +2,30 @@ import 'package:openapi/api.dart';
|
|||||||
|
|
||||||
class ServerInfoState {
|
class ServerInfoState {
|
||||||
final ServerVersionResponseDto serverVersion;
|
final ServerVersionResponseDto serverVersion;
|
||||||
|
final ServerFeaturesDto serverFeatures;
|
||||||
|
final ServerConfigDto serverConfig;
|
||||||
final bool isVersionMismatch;
|
final bool isVersionMismatch;
|
||||||
final String versionMismatchErrorMessage;
|
final String versionMismatchErrorMessage;
|
||||||
|
|
||||||
ServerInfoState({
|
ServerInfoState({
|
||||||
required this.serverVersion,
|
required this.serverVersion,
|
||||||
|
required this.serverFeatures,
|
||||||
|
required this.serverConfig,
|
||||||
required this.isVersionMismatch,
|
required this.isVersionMismatch,
|
||||||
required this.versionMismatchErrorMessage,
|
required this.versionMismatchErrorMessage,
|
||||||
});
|
});
|
||||||
|
|
||||||
ServerInfoState copyWith({
|
ServerInfoState copyWith({
|
||||||
ServerVersionResponseDto? serverVersion,
|
ServerVersionResponseDto? serverVersion,
|
||||||
|
ServerFeaturesDto? serverFeatures,
|
||||||
|
ServerConfigDto? serverConfig,
|
||||||
bool? isVersionMismatch,
|
bool? isVersionMismatch,
|
||||||
String? versionMismatchErrorMessage,
|
String? versionMismatchErrorMessage,
|
||||||
}) {
|
}) {
|
||||||
return ServerInfoState(
|
return ServerInfoState(
|
||||||
serverVersion: serverVersion ?? this.serverVersion,
|
serverVersion: serverVersion ?? this.serverVersion,
|
||||||
|
serverFeatures: serverFeatures ?? this.serverFeatures,
|
||||||
|
serverConfig: serverConfig ?? this.serverConfig,
|
||||||
isVersionMismatch: isVersionMismatch ?? this.isVersionMismatch,
|
isVersionMismatch: isVersionMismatch ?? this.isVersionMismatch,
|
||||||
versionMismatchErrorMessage:
|
versionMismatchErrorMessage:
|
||||||
versionMismatchErrorMessage ?? this.versionMismatchErrorMessage,
|
versionMismatchErrorMessage ?? this.versionMismatchErrorMessage,
|
||||||
@ -26,7 +34,7 @@ class ServerInfoState {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'ServerInfoState( serverVersion: $serverVersion, isVersionMismatch: $isVersionMismatch, versionMismatchErrorMessage: $versionMismatchErrorMessage)';
|
return 'ServerInfoState( serverVersion: $serverVersion, serverFeatures: $serverFeatures, serverConfig: $serverConfig, isVersionMismatch: $isVersionMismatch, versionMismatchErrorMessage: $versionMismatchErrorMessage)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -35,6 +43,8 @@ class ServerInfoState {
|
|||||||
|
|
||||||
return other is ServerInfoState &&
|
return other is ServerInfoState &&
|
||||||
other.serverVersion == serverVersion &&
|
other.serverVersion == serverVersion &&
|
||||||
|
other.serverFeatures == serverFeatures &&
|
||||||
|
other.serverConfig == serverConfig &&
|
||||||
other.isVersionMismatch == isVersionMismatch &&
|
other.isVersionMismatch == isVersionMismatch &&
|
||||||
other.versionMismatchErrorMessage == versionMismatchErrorMessage;
|
other.versionMismatchErrorMessage == versionMismatchErrorMessage;
|
||||||
}
|
}
|
||||||
@ -42,6 +52,8 @@ class ServerInfoState {
|
|||||||
@override
|
@override
|
||||||
int get hashCode {
|
int get hashCode {
|
||||||
return serverVersion.hashCode ^
|
return serverVersion.hashCode ^
|
||||||
|
serverFeatures.hashCode ^
|
||||||
|
serverConfig.hashCode ^
|
||||||
isVersionMismatch.hashCode ^
|
isVersionMismatch.hashCode ^
|
||||||
versionMismatchErrorMessage.hashCode;
|
versionMismatchErrorMessage.hashCode;
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,24 @@ class ServerInfoNotifier extends StateNotifier<ServerInfoState> {
|
|||||||
patch_: 0,
|
patch_: 0,
|
||||||
minor: 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,
|
isVersionMismatch: false,
|
||||||
versionMismatchErrorMessage: "",
|
versionMismatchErrorMessage: "",
|
||||||
),
|
),
|
||||||
@ -22,6 +40,12 @@ class ServerInfoNotifier extends StateNotifier<ServerInfoState> {
|
|||||||
|
|
||||||
final ServerInfoService _serverInfoService;
|
final ServerInfoService _serverInfoService;
|
||||||
|
|
||||||
|
getServerInfo() {
|
||||||
|
getServerVersion();
|
||||||
|
getServerFeatures();
|
||||||
|
getServerConfig();
|
||||||
|
}
|
||||||
|
|
||||||
getServerVersion() async {
|
getServerVersion() async {
|
||||||
ServerVersionResponseDto? serverVersion =
|
ServerVersionResponseDto? serverVersion =
|
||||||
await _serverInfoService.getServerVersion();
|
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) {
|
Map<String, int> _getDetailVersion(String version) {
|
||||||
List<String> detail = version.split(".");
|
List<String> detail = version.split(".");
|
||||||
|
|
||||||
|
@ -28,7 +28,25 @@ class ServerInfoService {
|
|||||||
try {
|
try {
|
||||||
return await _apiService.serverInfoApi.getServerVersion();
|
return await _apiService.serverInfoApi.getServerVersion();
|
||||||
} catch (e) {
|
} 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;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user