Compare commits

...

2 Commits

Author SHA1 Message Date
Alex
b69f6e0df7 Update inline font for f-droid publication metric (#107)
* Added local font
* Up Patch 1.5.1+9
2022-04-04 09:08:53 -05:00
Alex
be2794a372 Optimization/fix slow backup when asset list is long. (#104)
* Handle pause/restart listening to event on_upload_success and reload asset list after navigating back from BackupControllerPage
* Remove unused api endpoint
2022-04-03 12:31:45 -05:00
17 changed files with 67 additions and 95 deletions

View File

@@ -0,0 +1 @@
* Added inline font, remove google-font dependency in pubspec.

Binary file not shown.

Binary file not shown.

BIN
mobile/fonts/WorkSans.ttf Normal file

Binary file not shown.

View File

@@ -19,11 +19,11 @@ platform :ios do
desc "iOS Beta" desc "iOS Beta"
lane :beta do lane :beta do
increment_version_number( increment_version_number(
version_number: "1.5.0" version_number: "1.5.1"
)
increment_build_number(
build_number: latest_testflight_build_number + 1,
) )
increment_build_number({
build_number: 0
})
build_app(scheme: "Runner", build_app(scheme: "Runner",
workspace: "Runner.xcworkspace", workspace: "Runner.xcworkspace",
xcargs: "-allowProvisioningUpdates") xcargs: "-allowProvisioningUpdates")

View File

@@ -10,7 +10,6 @@ import 'package:immich_mobile/shared/providers/backup.provider.dart';
import 'package:immich_mobile/shared/providers/server_info.provider.dart'; import 'package:immich_mobile/shared/providers/server_info.provider.dart';
import 'package:immich_mobile/shared/providers/websocket.provider.dart'; import 'package:immich_mobile/shared/providers/websocket.provider.dart';
import 'constants/hive_box.dart'; import 'constants/hive_box.dart';
import 'package:google_fonts/google_fonts.dart';
void main() async { void main() async {
await Hive.initFlutter(); await Hive.initFlutter();
@@ -94,10 +93,11 @@ class _ImmichAppState extends ConsumerState<ImmichApp> with WidgetsBindingObserv
theme: ThemeData( theme: ThemeData(
brightness: Brightness.light, brightness: Brightness.light,
primarySwatch: Colors.indigo, primarySwatch: Colors.indigo,
textTheme: GoogleFonts.workSansTextTheme( // textTheme: GoogleFonts.workSansTextTheme(
Theme.of(context).textTheme.apply(fontSizeFactor: 1.0), // Theme.of(context).textTheme.apply(fontSizeFactor: 1.0),
), // ),
snackBarTheme: SnackBarThemeData(contentTextStyle: TextStyle(fontFamily: GoogleFonts.workSans().fontFamily)), fontFamily: 'WorkSans',
snackBarTheme: const SnackBarThemeData(contentTextStyle: TextStyle(fontFamily: 'WorkSans')),
scaffoldBackgroundColor: const Color(0xFFf6f8fe), scaffoldBackgroundColor: const Color(0xFFf6f8fe),
appBarTheme: const AppBarTheme( appBarTheme: const AppBarTheme(
backgroundColor: Colors.white, backgroundColor: Colors.white,

View File

@@ -1,7 +1,6 @@
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:badges/badges.dart'; import 'package:badges/badges.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart'; import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
@@ -79,12 +78,11 @@ class ImmichSliverAppBar extends ConsumerWidget {
), ),
title: Text( title: Text(
'IMMICH', 'IMMICH',
style: GoogleFonts.snowburstOne( style: TextStyle(
textStyle: TextStyle( fontFamily: 'SnowburstOne',
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 22, fontSize: 22,
color: Theme.of(context).primaryColor, color: Theme.of(context).primaryColor,
),
), ),
), ),
actions: [ actions: [
@@ -121,8 +119,12 @@ class ImmichSliverAppBar extends ConsumerWidget {
), ),
child: const Icon(Icons.backup_rounded)), child: const Icon(Icons.backup_rounded)),
tooltip: 'Backup Controller', tooltip: 'Backup Controller',
onPressed: () { onPressed: () async {
AutoRouter.of(context).push(const BackupControllerRoute()); var onPop = await AutoRouter.of(context).push(const BackupControllerRoute());
if (onPop != null && onPop == true) {
onPopBack!();
}
}, },
), ),
_backupState.backupProgress == BackUpProgressEnum.inProgress _backupState.backupProgress == BackUpProgressEnum.inProgress

View File

@@ -33,6 +33,10 @@ class HomePage extends HookConsumerWidget {
return null; return null;
}, []); }, []);
void reloadAllAsset() {
ref.read(assetProvider.notifier).getAllAsset();
}
Widget _buildBody() { Widget _buildBody() {
if (assetGroupByDateTime.isNotEmpty) { if (assetGroupByDateTime.isNotEmpty) {
int? lastMonth; int? lastMonth;
@@ -86,7 +90,9 @@ class HomePage extends HookConsumerWidget {
child: null, child: null,
), ),
) )
: const ImmichSliverAppBar(), : ImmichSliverAppBar(
onPopBack: reloadAllAsset,
),
duration: const Duration(milliseconds: 350), duration: const Duration(milliseconds: 350),
), ),
..._imageGridGroup ..._imageGridGroup

View File

@@ -1,7 +1,6 @@
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/home/providers/asset.provider.dart'; import 'package:immich_mobile/modules/home/providers/asset.provider.dart';
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart'; import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
@@ -33,9 +32,12 @@ class LoginForm extends HookConsumerWidget {
), ),
Text( Text(
'IMMICH', 'IMMICH',
style: GoogleFonts.snowburstOne( style: TextStyle(
textStyle: fontFamily: 'SnowburstOne',
TextStyle(fontWeight: FontWeight.bold, fontSize: 48, color: Theme.of(context).primaryColor)), fontWeight: FontWeight.bold,
fontSize: 48,
color: Theme.of(context).primaryColor,
),
), ),
EmailInput(controller: usernameController), EmailInput(controller: usernameController),
PasswordInput(controller: passwordController), PasswordInput(controller: passwordController),

View File

@@ -106,6 +106,20 @@ class WebsocketNotifier extends StateNotifier<WebscoketState> {
} }
} }
} }
stopListenToEvent(String eventName) {
debugPrint("[Websocket] Stop listening to event $eventName");
state.socket?.off(eventName);
}
listenUploadEvent() {
debugPrint("[Websocket] Start listening to event on_upload_success");
state.socket?.on('on_upload_success', (data) {
var jsonString = jsonDecode(data.toString());
ImmichAsset newAsset = ImmichAsset.fromMap(jsonString);
ref.watch(assetProvider.notifier).onNewAssetUploaded(newAsset);
});
}
} }
final websocketProvider = StateNotifierProvider<WebsocketNotifier, WebscoketState>((ref) { final websocketProvider = StateNotifierProvider<WebsocketNotifier, WebscoketState>((ref) {

View File

@@ -6,6 +6,7 @@ import 'package:immich_mobile/modules/login/models/authentication_state.model.da
import 'package:immich_mobile/shared/models/backup_state.model.dart'; import 'package:immich_mobile/shared/models/backup_state.model.dart';
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart'; import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
import 'package:immich_mobile/shared/providers/backup.provider.dart'; import 'package:immich_mobile/shared/providers/backup.provider.dart';
import 'package:immich_mobile/shared/providers/websocket.provider.dart';
import 'package:percent_indicator/linear_percent_indicator.dart'; import 'package:percent_indicator/linear_percent_indicator.dart';
class BackupControllerPage extends HookConsumerWidget { class BackupControllerPage extends HookConsumerWidget {
@@ -23,6 +24,7 @@ class BackupControllerPage extends HookConsumerWidget {
ref.read(backupProvider.notifier).getBackupInfo(); ref.read(backupProvider.notifier).getBackupInfo();
} }
ref.watch(websocketProvider.notifier).stopListenToEvent('on_upload_success');
return null; return null;
}, []); }, []);
@@ -107,6 +109,7 @@ class BackupControllerPage extends HookConsumerWidget {
), ),
leading: IconButton( leading: IconButton(
onPressed: () { onPressed: () {
ref.watch(websocketProvider.notifier).listenUploadEvent();
AutoRouter.of(context).pop(true); AutoRouter.of(context).pop(true);
}, },
icon: const Icon(Icons.arrow_back_ios_rounded)), icon: const Icon(Icons.arrow_back_ios_rounded)),

View File

@@ -373,13 +373,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.2" version: "2.0.2"
google_fonts:
dependency: "direct main"
description:
name: google_fonts
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.0"
graphs: graphs:
dependency: transitive dependency: transitive
description: description:

View File

@@ -2,7 +2,7 @@ name: immich_mobile
description: Immich - selfhosted backup media file on mobile phone description: Immich - selfhosted backup media file on mobile phone
publish_to: "none" publish_to: "none"
version: 1.5.0+8 version: 1.5.1+9
environment: environment:
sdk: ">=2.15.1 <3.0.0" sdk: ">=2.15.1 <3.0.0"
@@ -18,7 +18,7 @@ dependencies:
hive_flutter: hive_flutter:
dio: ^4.0.4 dio: ^4.0.4
cached_network_image: ^3.2.0 cached_network_image: ^3.2.0
google_fonts: ^2.2.0 # google_fonts: ^2.2.0
percent_indicator: ^3.4.0 percent_indicator: ^3.4.0
intl: ^0.17.0 intl: ^0.17.0
auto_route: ^3.2.2 auto_route: ^3.2.2
@@ -50,6 +50,15 @@ flutter:
uses-material-design: true uses-material-design: true
assets: assets:
- assets/ - assets/
fonts:
- family: WorkSans
fonts:
- asset: fonts/WorkSans.ttf
- asset: fonts/WorkSans-Italic.ttf
style: italic
- family: SnowburstOne
fonts:
- asset: fonts/SnowburstOne.ttf
flutter_icons: flutter_icons:
image_path_android: "assets/immich-logo-no-outline.png" image_path_android: "assets/immich-logo-no-outline.png"

View File

@@ -1,6 +1,6 @@
{ {
"name": "immich", "name": "immich",
"version": "1.3.2", "version": "1.5.1",
"description": "", "description": "",
"author": "", "author": "",
"private": true, "private": true,

View File

@@ -115,18 +115,8 @@ export class AssetController {
return this.assetService.searchAsset(authUser, searchAssetDto); return this.assetService.searchAsset(authUser, searchAssetDto);
} }
@Get('/new')
async getNewAssets(@GetAuthUser() authUser: AuthUserDto, @Query(ValidationPipe) query: GetNewAssetQueryDto) {
return await this.assetService.getNewAssets(authUser, query.latestDate);
}
@Get('/all')
async getAllAssets(@GetAuthUser() authUser: AuthUserDto, @Query(ValidationPipe) query: GetAllAssetQueryDto) {
return await this.assetService.getAllAssets(authUser, query);
}
@Get('/') @Get('/')
async getAllAssetsNoPagination(@GetAuthUser() authUser: AuthUserDto) { async getAllAssets(@GetAuthUser() authUser: AuthUserDto) {
return await this.assetService.getAllAssetsNoPagination(authUser); return await this.assetService.getAllAssetsNoPagination(authUser);
} }
@@ -137,7 +127,7 @@ export class AssetController {
@Get('/assetById/:assetId') @Get('/assetById/:assetId')
async getAssetById(@GetAuthUser() authUser: AuthUserDto, @Param('assetId') assetId) { async getAssetById(@GetAuthUser() authUser: AuthUserDto, @Param('assetId') assetId) {
return this.assetService.getAssetById(authUser, assetId); return await this.assetService.getAssetById(authUser, assetId);
} }
@Delete('/') @Delete('/')

View File

@@ -76,42 +76,6 @@ export class AssetService {
} }
} }
public async getAllAssets(authUser: AuthUserDto, query: GetAllAssetQueryDto): Promise<GetAllAssetReponseDto> {
try {
const assets = await this.assetRepository
.createQueryBuilder('a')
.where('a."userId" = :userId', { userId: authUser.id })
.andWhere('a."createdAt" < :lastQueryCreatedAt', {
lastQueryCreatedAt: query.nextPageKey || new Date().toISOString(),
})
.orderBy('a."createdAt"::date', 'DESC')
.take(5000)
.getMany();
if (assets.length > 0) {
const data = _.groupBy(assets, (a) => new Date(a.createdAt).toISOString().slice(0, 10));
const formattedData = [];
Object.keys(data).forEach((v) => formattedData.push({ date: v, assets: data[v] }));
const response = new GetAllAssetReponseDto();
response.count = assets.length;
response.data = formattedData;
response.nextPageKey = assets[assets.length - 1].createdAt;
return response;
} else {
const response = new GetAllAssetReponseDto();
response.count = 0;
response.data = [];
response.nextPageKey = 'null';
return response;
}
} catch (e) {
Logger.error(e, 'getAllAssets');
}
}
public async findOne(authUser: AuthUserDto, deviceId: string, assetId: string): Promise<AssetEntity> { public async findOne(authUser: AuthUserDto, deviceId: string, assetId: string): Promise<AssetEntity> {
const rows = await this.assetRepository.query( const rows = await this.assetRepository.query(
'SELECT * FROM assets a WHERE a."deviceAssetId" = $1 AND a."userId" = $2 AND a."deviceId" = $3', 'SELECT * FROM assets a WHERE a."deviceAssetId" = $1 AND a."userId" = $2 AND a."deviceId" = $3',
@@ -125,18 +89,6 @@ export class AssetService {
return rows[0] as AssetEntity; return rows[0] as AssetEntity;
} }
public async getNewAssets(authUser: AuthUserDto, latestDate: string) {
return await this.assetRepository.find({
where: {
userId: authUser.id,
createdAt: MoreThan(latestDate),
},
order: {
createdAt: 'ASC', // ASC order to add existed asset the latest group first before creating a new date group.
},
});
}
public async getAssetById(authUser: AuthUserDto, assetId: string) { public async getAssetById(authUser: AuthUserDto, assetId: string) {
return await this.assetRepository.findOne({ return await this.assetRepository.findOne({
where: { where: {

View File

@@ -4,6 +4,6 @@
export const serverVersion = { export const serverVersion = {
major: 1, major: 1,
minor: 5, minor: 5,
patch: 0, patch: 1,
build: 8, build: 9,
}; };