mirror of
https://github.com/immich-app/immich.git
synced 2025-06-01 04:36:19 -04:00
chore(mobile): small visual fix and update (#17547)
* chore(mobile): small visual fix and update * update * update * remove design placeholder
This commit is contained in:
parent
1f18fe31f0
commit
ab2a7006f9
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"open": "Open",
|
||||||
"action_common_back": "Back",
|
"action_common_back": "Back",
|
||||||
"action_common_cancel": "Cancel",
|
"action_common_cancel": "Cancel",
|
||||||
"action_common_clear": "Clear",
|
"action_common_clear": "Clear",
|
||||||
@ -312,7 +313,7 @@
|
|||||||
"home_page_delete_remote_err_local": "Local assets in delete remote selection, skipping",
|
"home_page_delete_remote_err_local": "Local assets in delete remote selection, skipping",
|
||||||
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
|
"home_page_favorite_err_local": "Can not favorite local assets yet, skipping",
|
||||||
"home_page_favorite_err_partner": "Can not favorite partner assets yet, skipping",
|
"home_page_favorite_err_partner": "Can not favorite partner assets yet, skipping",
|
||||||
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s).",
|
"home_page_first_time_notice": "If this is your first time using the app, please make sure to choose a backup album so that the timeline can populate photos and videos in it",
|
||||||
"home_page_share_err_local": "Can not share local assets via link, skipping",
|
"home_page_share_err_local": "Can not share local assets via link, skipping",
|
||||||
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
|
"home_page_upload_err_limit": "Can only upload a maximum of 30 assets at a time, skipping",
|
||||||
"ignore_icloud_photos": "Ignore iCloud photos",
|
"ignore_icloud_photos": "Ignore iCloud photos",
|
||||||
@ -693,4 +694,4 @@
|
|||||||
"viewer_unstack": "Un-Stack",
|
"viewer_unstack": "Un-Stack",
|
||||||
"wifi_name": "WiFi Name",
|
"wifi_name": "WiFi Name",
|
||||||
"your_wifi_name": "Your WiFi name"
|
"your_wifi_name": "Your WiFi name"
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,25 @@ PODS:
|
|||||||
- sqflite_darwin (0.0.4):
|
- sqflite_darwin (0.0.4):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
- sqlite3 (3.49.1):
|
||||||
|
- sqlite3/common (= 3.49.1)
|
||||||
|
- sqlite3/common (3.49.1)
|
||||||
|
- sqlite3/dbstatvtab (3.49.1):
|
||||||
|
- sqlite3/common
|
||||||
|
- sqlite3/fts5 (3.49.1):
|
||||||
|
- sqlite3/common
|
||||||
|
- sqlite3/perf-threadsafe (3.49.1):
|
||||||
|
- sqlite3/common
|
||||||
|
- sqlite3/rtree (3.49.1):
|
||||||
|
- sqlite3/common
|
||||||
|
- sqlite3_flutter_libs (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
|
- sqlite3 (~> 3.49.1)
|
||||||
|
- sqlite3/dbstatvtab
|
||||||
|
- sqlite3/fts5
|
||||||
|
- sqlite3/perf-threadsafe
|
||||||
|
- sqlite3/rtree
|
||||||
- SwiftyGif (5.4.5)
|
- SwiftyGif (5.4.5)
|
||||||
- url_launcher_ios (0.0.1):
|
- url_launcher_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
@ -130,6 +149,7 @@ DEPENDENCIES:
|
|||||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
||||||
|
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`)
|
||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||||
|
|
||||||
@ -140,6 +160,7 @@ SPEC REPOS:
|
|||||||
- MapLibre
|
- MapLibre
|
||||||
- SAMKeychain
|
- SAMKeychain
|
||||||
- SDWebImage
|
- SDWebImage
|
||||||
|
- sqlite3
|
||||||
- SwiftyGif
|
- SwiftyGif
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
@ -195,6 +216,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||||
sqflite_darwin:
|
sqflite_darwin:
|
||||||
:path: ".symlinks/plugins/sqflite_darwin/darwin"
|
:path: ".symlinks/plugins/sqflite_darwin/darwin"
|
||||||
|
sqlite3_flutter_libs:
|
||||||
|
:path: ".symlinks/plugins/sqlite3_flutter_libs/darwin"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||||
wakelock_plus:
|
wakelock_plus:
|
||||||
@ -232,6 +255,8 @@ SPEC CHECKSUMS:
|
|||||||
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
||||||
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
|
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
|
||||||
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
||||||
|
sqlite3: fc1400008a9b3525f5914ed715a5d1af0b8f4983
|
||||||
|
sqlite3_flutter_libs: f8fc13346870e73fe35ebf6dbb997fbcd156b241
|
||||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||||
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
||||||
wakelock_plus: 04623e3f525556020ebd4034310f20fe7fda8b49
|
wakelock_plus: 04623e3f525556020ebd4034310f20fe7fda8b49
|
||||||
|
@ -10,7 +10,6 @@ import 'package:immich_mobile/services/app_settings.service.dart';
|
|||||||
import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart';
|
import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart';
|
||||||
import 'package:immich_mobile/widgets/backup/album_info_card.dart';
|
import 'package:immich_mobile/widgets/backup/album_info_card.dart';
|
||||||
import 'package:immich_mobile/widgets/backup/album_info_list_tile.dart';
|
import 'package:immich_mobile/widgets/backup/album_info_list_tile.dart';
|
||||||
import 'package:immich_mobile/widgets/common/immich_loading_indicator.dart';
|
|
||||||
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
|
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
@ -37,7 +36,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
|
|||||||
if (albums.isEmpty) {
|
if (albums.isEmpty) {
|
||||||
return const SliverToBoxAdapter(
|
return const SliverToBoxAdapter(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: ImmichLoadingIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -61,7 +60,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
|
|||||||
if (albums.isEmpty) {
|
if (albums.isEmpty) {
|
||||||
return const SliverToBoxAdapter(
|
return const SliverToBoxAdapter(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: ImmichLoadingIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -53,28 +53,29 @@ class PhotosPage extends HookConsumerWidget {
|
|||||||
padding: const EdgeInsets.only(top: 16.0),
|
padding: const EdgeInsets.only(top: 16.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'home_page_building_timeline',
|
'home_page_building_timeline',
|
||||||
style: TextStyle(
|
style: context.textTheme.titleMedium?.copyWith(
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
fontSize: 16,
|
|
||||||
color: context.primaryColor,
|
color: context.primaryColor,
|
||||||
),
|
),
|
||||||
).tr(),
|
).tr(),
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
AnimatedOpacity(
|
AnimatedOpacity(
|
||||||
duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 1000),
|
||||||
opacity: tipOneOpacity.value,
|
opacity: tipOneOpacity.value,
|
||||||
child: SizedBox(
|
child: Column(
|
||||||
width: 250,
|
children: [
|
||||||
child: Padding(
|
SizedBox(
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
width: 320,
|
||||||
child: const Text(
|
child: Padding(
|
||||||
'home_page_first_time_notice',
|
padding: const EdgeInsets.only(top: 8.0),
|
||||||
textAlign: TextAlign.justify,
|
child: Text(
|
||||||
style: TextStyle(
|
'home_page_first_time_notice',
|
||||||
fontSize: 12,
|
textAlign: TextAlign.center,
|
||||||
|
style: context.textTheme.bodyMedium,
|
||||||
|
).tr(),
|
||||||
),
|
),
|
||||||
).tr(),
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -715,7 +715,7 @@ class SearchPage extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
if (isSearching.value)
|
if (isSearching.value)
|
||||||
const Expanded(
|
const Expanded(
|
||||||
child: Center(child: CircularProgressIndicator.adaptive()),
|
child: Center(child: CircularProgressIndicator()),
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
SearchResultGrid(
|
SearchResultGrid(
|
||||||
|
@ -163,6 +163,13 @@ ThemeData getThemeData({
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
dialogTheme: DialogThemeData(backgroundColor: colorScheme.surfaceContainer),
|
dialogTheme: DialogThemeData(backgroundColor: colorScheme.surfaceContainer),
|
||||||
|
progressIndicatorTheme: const ProgressIndicatorThemeData(
|
||||||
|
// ignore: deprecated_member_use
|
||||||
|
year2023: false,
|
||||||
|
// TODO: Uncommented after upgrade to version later than 3.29.2
|
||||||
|
// circularTrackColor: Colors.black12,
|
||||||
|
trackGap: 3,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ import 'package:immich_mobile/entities/album.entity.dart';
|
|||||||
import 'package:immich_mobile/entities/asset.entity.dart';
|
import 'package:immich_mobile/entities/asset.entity.dart';
|
||||||
import 'package:immich_mobile/providers/asset.provider.dart';
|
import 'package:immich_mobile/providers/asset.provider.dart';
|
||||||
import 'package:immich_mobile/providers/user.provider.dart';
|
import 'package:immich_mobile/providers/user.provider.dart';
|
||||||
import 'package:immich_mobile/widgets/common/immich_loading_indicator.dart';
|
|
||||||
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
||||||
import 'package:immich_mobile/utils/immich_loading_overlay.dart';
|
import 'package:immich_mobile/utils/immich_loading_overlay.dart';
|
||||||
import 'package:immich_mobile/utils/selection_handlers.dart';
|
import 'package:immich_mobile/utils/selection_handlers.dart';
|
||||||
@ -59,7 +58,7 @@ class MultiselectGrid extends HookConsumerWidget {
|
|||||||
final bool editEnabled;
|
final bool editEnabled;
|
||||||
final Widget? emptyIndicator;
|
final Widget? emptyIndicator;
|
||||||
Widget buildDefaultLoadingIndicator() =>
|
Widget buildDefaultLoadingIndicator() =>
|
||||||
const Center(child: ImmichLoadingIndicator());
|
const Center(child: CircularProgressIndicator());
|
||||||
|
|
||||||
Widget buildEmptyIndicator() =>
|
Widget buildEmptyIndicator() =>
|
||||||
emptyIndicator ?? Center(child: const Text("no_assets_to_show").tr());
|
emptyIndicator ?? Center(child: const Text("no_assets_to_show").tr());
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:immich_mobile/widgets/common/immich_logo.dart';
|
||||||
|
|
||||||
class ImmichLoadingIndicator extends StatelessWidget {
|
class ImmichLoadingIndicator extends HookWidget {
|
||||||
final double? borderRadius;
|
final double? borderRadius;
|
||||||
|
|
||||||
const ImmichLoadingIndicator({
|
const ImmichLoadingIndicator({
|
||||||
@ -11,18 +12,109 @@ class ImmichLoadingIndicator extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final logoAnimationController = useAnimationController(
|
||||||
|
duration: const Duration(seconds: 6),
|
||||||
|
)
|
||||||
|
..reverse()
|
||||||
|
..repeat();
|
||||||
|
|
||||||
|
final borderAnimationController = useAnimationController(
|
||||||
|
duration: const Duration(seconds: 6),
|
||||||
|
)..repeat();
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
height: 60,
|
height: 80,
|
||||||
width: 60,
|
width: 80,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: context.primaryColor.withAlpha(200),
|
color: Colors.transparent,
|
||||||
borderRadius: BorderRadius.circular(borderRadius ?? 10),
|
borderRadius: BorderRadius.circular(borderRadius ?? 50),
|
||||||
|
backgroundBlendMode: BlendMode.luminosity,
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.all(15),
|
child: AnimatedBuilder(
|
||||||
child: const CircularProgressIndicator(
|
animation: borderAnimationController,
|
||||||
color: Colors.white,
|
builder: (context, child) {
|
||||||
strokeWidth: 3,
|
return CustomPaint(
|
||||||
|
painter: GradientBorderPainter(
|
||||||
|
animation: borderAnimationController.value,
|
||||||
|
strokeWidth: 3,
|
||||||
|
),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(15),
|
||||||
|
child: RotationTransition(
|
||||||
|
turns: logoAnimationController,
|
||||||
|
child: const ImmichLogo(
|
||||||
|
heroTag: 'logo',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class GradientBorderPainter extends CustomPainter {
|
||||||
|
final double animation;
|
||||||
|
final double strokeWidth;
|
||||||
|
final double opacity = 0.7;
|
||||||
|
final colors = [
|
||||||
|
const Color(0xFFFA2921),
|
||||||
|
const Color(0xFFED79B5),
|
||||||
|
const Color(0xFFFFB400),
|
||||||
|
const Color(0xFF1E83F7),
|
||||||
|
const Color(0xFF18C249),
|
||||||
|
];
|
||||||
|
|
||||||
|
GradientBorderPainter({
|
||||||
|
required this.animation,
|
||||||
|
required this.strokeWidth,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
void paint(Canvas canvas, Size size) {
|
||||||
|
final center = Offset(size.width / 2, size.height / 2);
|
||||||
|
final radius = min(size.width, size.height) / 2 - strokeWidth / 2;
|
||||||
|
|
||||||
|
// Create a sweep gradient that covers the entire circle
|
||||||
|
final Rect rect = Rect.fromCircle(center: center, radius: radius);
|
||||||
|
|
||||||
|
// Create a paint with the gradient
|
||||||
|
final paint = Paint()
|
||||||
|
..style = PaintingStyle.stroke
|
||||||
|
..strokeWidth = strokeWidth;
|
||||||
|
|
||||||
|
// Create a gradient that smoothly transitions between colors
|
||||||
|
final shader = SweepGradient(
|
||||||
|
// Use a fixed starting point and let matrix transformation handle rotation
|
||||||
|
startAngle: 0,
|
||||||
|
endAngle: 2 * 3.14159,
|
||||||
|
colors: [
|
||||||
|
// Repeat colors to ensure smooth transitions
|
||||||
|
...colors.map((c) => c.withValues(alpha: opacity)),
|
||||||
|
colors.first.withValues(alpha: opacity),
|
||||||
|
],
|
||||||
|
// Add evenly distributed stops
|
||||||
|
stops: List.generate(
|
||||||
|
colors.length + 1,
|
||||||
|
(index) => index / colors.length,
|
||||||
|
),
|
||||||
|
tileMode: TileMode.clamp,
|
||||||
|
// Use transformations to rotate the gradient
|
||||||
|
transform: GradientRotation(-animation * 2 * 3.14159),
|
||||||
|
).createShader(rect);
|
||||||
|
|
||||||
|
paint.shader = shader;
|
||||||
|
|
||||||
|
// Draw the circular border
|
||||||
|
canvas.drawCircle(center, radius, paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRepaint(GradientBorderPainter oldDelegate) {
|
||||||
|
return animation != oldDelegate.animation;
|
||||||
|
}
|
||||||
|
|
||||||
|
double min(double a, double b) => a < b ? a : b;
|
||||||
|
}
|
||||||
|
@ -303,7 +303,7 @@ class LoginForm extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
onPressed: () => context.pushRoute(const SettingsRoute()),
|
onPressed: () => context.pushRoute(const SettingsRoute()),
|
||||||
icon: const Icon(Icons.settings_rounded),
|
icon: const Icon(Icons.settings_rounded),
|
||||||
label: const SizedBox.shrink(),
|
label: const Text(""),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 1),
|
const SizedBox(width: 1),
|
||||||
|
@ -13,7 +13,6 @@ import 'package:immich_mobile/widgets/settings/settings_button_list_tile.dart';
|
|||||||
import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart';
|
import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart';
|
||||||
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
|
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
|
||||||
import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart';
|
import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart';
|
||||||
import 'package:immich_mobile/widgets/common/immich_loading_indicator.dart';
|
|
||||||
|
|
||||||
class BackupSettings extends HookConsumerWidget {
|
class BackupSettings extends HookConsumerWidget {
|
||||||
const BackupSettings({
|
const BackupSettings({
|
||||||
@ -59,7 +58,7 @@ class BackupSettings extends HookConsumerWidget {
|
|||||||
? const Column(
|
? const Column(
|
||||||
children: [
|
children: [
|
||||||
SizedBox(height: 20),
|
SizedBox(height: 20),
|
||||||
Center(child: ImmichLoadingIndicator()),
|
Center(child: CircularProgressIndicator()),
|
||||||
SizedBox(height: 20),
|
SizedBox(height: 20),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@ -83,9 +82,7 @@ class BackupSettings extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
buttonText: 'sync_albums'.tr(),
|
buttonText: 'sync_albums'.tr(),
|
||||||
child: isAlbumSyncInProgress.value
|
child: isAlbumSyncInProgress.value
|
||||||
? const CircularProgressIndicator.adaptive(
|
? const CircularProgressIndicator()
|
||||||
strokeWidth: 2,
|
|
||||||
)
|
|
||||||
: ElevatedButton(
|
: ElevatedButton(
|
||||||
onPressed: syncAlbums,
|
onPressed: syncAlbums,
|
||||||
child: Text('sync'.tr()),
|
child: Text('sync'.tr()),
|
||||||
|
@ -1320,6 +1320,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.0"
|
version: "1.5.0"
|
||||||
|
punycode:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: punycode
|
||||||
|
sha256: "39b874cc1f78b94e57db17e74b3f2ba2a96e25c0bebdcc8a571614dccda0ff0c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
recase:
|
recase:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user