mirror of https://github.com/immich-app/immich.git
Add reverse geocoding and show asset location on map in detail view (#43)
* Added reserve geocoding, location in search suggestion, and search by location * Added mapbox sdk to app * Added mapbox to image detailed viewpull/36/head
parent
251c92ff1e
commit
026f3c24e9
@ -1,39 +1,23 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.immich_mobile">
|
||||
<application
|
||||
android:label="Immich"
|
||||
android:name="${applicationName}"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.immich_mobile">
|
||||
<application android:label="Immich" android:name="${applicationName}" android:usesCleartextTraffic="true" android:icon="@mipmap/ic_launcher">
|
||||
<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
<meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2"/>
|
||||
<meta-data android:name="flutterEmbedding" android:value="2" />
|
||||
|
||||
|
||||
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
</manifest>
|
||||
@ -1,3 +1,3 @@
|
||||
org.gradle.jvmargs=-Xmx1536M
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
android.enableJetifier=true
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
@ -0,0 +1,51 @@
|
||||
import 'dart:convert';
|
||||
|
||||
class MapboxInfo {
|
||||
final bool isEnable;
|
||||
final String mapboxSecret;
|
||||
MapboxInfo({
|
||||
required this.isEnable,
|
||||
required this.mapboxSecret,
|
||||
});
|
||||
|
||||
MapboxInfo copyWith({
|
||||
bool? isEnable,
|
||||
String? mapboxSecret,
|
||||
}) {
|
||||
return MapboxInfo(
|
||||
isEnable: isEnable ?? this.isEnable,
|
||||
mapboxSecret: mapboxSecret ?? this.mapboxSecret,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'isEnable': isEnable,
|
||||
'mapboxSecret': mapboxSecret,
|
||||
};
|
||||
}
|
||||
|
||||
factory MapboxInfo.fromMap(Map<String, dynamic> map) {
|
||||
return MapboxInfo(
|
||||
isEnable: map['isEnable'] ?? false,
|
||||
mapboxSecret: map['mapboxSecret'] ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory MapboxInfo.fromJson(String source) => MapboxInfo.fromMap(json.decode(source));
|
||||
|
||||
@override
|
||||
String toString() => 'MapboxInfo(isEnable: $isEnable, mapboxSecret: $mapboxSecret)';
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is MapboxInfo && other.isEnable == isEnable && other.mapboxSecret == mapboxSecret;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => isEnable.hashCode ^ mapboxSecret.hashCode;
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
import 'package:immich_mobile/shared/models/mapbox_info.model.dart';
|
||||
import 'package:immich_mobile/shared/services/server_info.service.dart';
|
||||
|
||||
class ServerInfoState {
|
||||
final MapboxInfo mapboxInfo;
|
||||
ServerInfoState({
|
||||
required this.mapboxInfo,
|
||||
});
|
||||
|
||||
ServerInfoState copyWith({
|
||||
MapboxInfo? mapboxInfo,
|
||||
}) {
|
||||
return ServerInfoState(
|
||||
mapboxInfo: mapboxInfo ?? this.mapboxInfo,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'mapboxInfo': mapboxInfo.toMap(),
|
||||
};
|
||||
}
|
||||
|
||||
factory ServerInfoState.fromMap(Map<String, dynamic> map) {
|
||||
return ServerInfoState(
|
||||
mapboxInfo: MapboxInfo.fromMap(map['mapboxInfo']),
|
||||
);
|
||||
}
|
||||
|
||||
String toJson() => json.encode(toMap());
|
||||
|
||||
factory ServerInfoState.fromJson(String source) => ServerInfoState.fromMap(json.decode(source));
|
||||
|
||||
@override
|
||||
String toString() => 'ServerInfoState(mapboxInfo: $mapboxInfo)';
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
|
||||
return other is ServerInfoState && other.mapboxInfo == mapboxInfo;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => mapboxInfo.hashCode;
|
||||
}
|
||||
|
||||
class ServerInfoNotifier extends StateNotifier<ServerInfoState> {
|
||||
ServerInfoNotifier()
|
||||
: super(
|
||||
ServerInfoState(
|
||||
mapboxInfo: MapboxInfo(isEnable: false, mapboxSecret: ""),
|
||||
),
|
||||
);
|
||||
|
||||
final ServerInfoService _serverInfoService = ServerInfoService();
|
||||
|
||||
getMapboxInfo() async {
|
||||
MapboxInfo mapboxInfoRes = await _serverInfoService.getMapboxInfo();
|
||||
print(mapboxInfoRes);
|
||||
state = state.copyWith(mapboxInfo: mapboxInfoRes);
|
||||
}
|
||||
}
|
||||
|
||||
final serverInfoProvider = StateNotifierProvider<ServerInfoNotifier, ServerInfoState>((ref) {
|
||||
return ServerInfoNotifier();
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,29 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddRegionCityToExIf1646709533213 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE exif
|
||||
ADD COLUMN city varchar;
|
||||
|
||||
ALTER TABLE exif
|
||||
ADD COLUMN state varchar;
|
||||
|
||||
ALTER TABLE exif
|
||||
ADD COLUMN country varchar;
|
||||
`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE exif
|
||||
DROP COLUMN city;
|
||||
|
||||
ALTER TABLE exif
|
||||
DROP COLUMN state;
|
||||
|
||||
ALTER TABLE exif
|
||||
DROP COLUMN country;
|
||||
`);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
|
||||
export class AddLocationToExifTextSearch1646710459852 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE exif
|
||||
DROP COLUMN IF EXISTS exif_text_searchable_column;
|
||||
|
||||
ALTER TABLE exif
|
||||
ADD COLUMN IF NOT EXISTS exif_text_searchable_column tsvector
|
||||
GENERATED ALWAYS AS (
|
||||
TO_TSVECTOR('english',
|
||||
COALESCE(make, '') || ' ' ||
|
||||
COALESCE(model, '') || ' ' ||
|
||||
COALESCE(orientation, '') || ' ' ||
|
||||
COALESCE("lensModel", '') || ' ' ||
|
||||
COALESCE("city", '') || ' ' ||
|
||||
COALESCE("state", '') || ' ' ||
|
||||
COALESCE("country", '')
|
||||
)
|
||||
) STORED;
|
||||
|
||||
CREATE INDEX exif_text_searchable_idx
|
||||
ON exif
|
||||
USING GIN (exif_text_searchable_column);
|
||||
`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`
|
||||
ALTER TABLE exif
|
||||
DROP COLUMN IF EXISTS exif_text_searchable_column;
|
||||
|
||||
DROP INDEX IF EXISTS exif_text_searchable_idx ON exif;
|
||||
`);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue