app bar and log details page

This commit is contained in:
shenlong-tanwen 2024-10-24 01:46:10 +05:30
parent a0afea04d8
commit 5385d43c8c
12 changed files with 183 additions and 8 deletions

View File

@ -38,9 +38,17 @@
},
"logs": {
"title": "Logs",
"no_logs": "No logs available"
"no_logs": "No logs available",
"detail": {
"title": "Log Detail",
"message_heading": "MESSAGE",
"context_heading": "CONTEXT",
"error_heading": "ERROR",
"stack_heading": "STACK TRACE"
}
},
"common": {
"loading": "Loading"
"loading": "Loading",
"copied_long": "Copied to clipboard"
}
}

View File

@ -1,5 +1,10 @@
import 'package:flutter/material.dart';
import 'package:immich_mobile/i18n/strings.g.dart';
import 'package:immich_mobile/presentation/components/common/gap.widget.dart';
import 'package:immich_mobile/presentation/components/common/user_avatar.widget.dart';
import 'package:immich_mobile/presentation/components/image/immich_logo.widget.dart';
import 'package:immich_mobile/presentation/states/current_user.state.dart';
import 'package:immich_mobile/service_locator.dart';
import 'package:immich_mobile/utils/constants/size_constants.dart';
import 'package:immich_mobile/utils/extensions/build_context.extension.dart';
class ImAppBar extends StatelessWidget implements PreferredSizeWidget {
@ -11,10 +16,26 @@ class ImAppBar extends StatelessWidget implements PreferredSizeWidget {
@override
Widget build(BuildContext context) {
return AppBar(
backgroundColor: context.theme.appBarTheme.backgroundColor,
automaticallyImplyLeading: false,
title: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ImLogo(dimension: SizeConstants.xm),
SizedGap.sw(),
ImLogoText(fontSize: 20),
],
),
actions: [
Padding(
padding: const EdgeInsets.only(right: SizeConstants.m),
child: ImUserAvatar(
user: di<CurrentUserProvider>().value,
radius: SizeConstants.m,
),
),
],
backgroundColor: context.theme.appBarTheme.backgroundColor,
centerTitle: false,
title: Text(context.t.immich),
);
}
}

View File

@ -65,6 +65,8 @@ class _ImAssetGridState extends State<ImAssetGrid> {
BlocBuilder<AssetGridCubit, AssetGridState>(
builder: (_, state) {
final elements = state.renderList.elements;
// Append padding if required
if (widget.topPadding != null &&
elements.firstOrNull is! RenderListPaddingElement) {
elements.insert(
@ -74,6 +76,9 @@ class _ImAssetGridState extends State<ImAssetGrid> {
before: elements.firstOrNull,
),
);
} else if (widget.topPadding == null &&
elements.firstOrNull is RenderListPaddingElement) {
elements.removeAt(0);
}
final grid = FlutterListView(

View File

@ -0,0 +1,128 @@
import 'dart:async';
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:immich_mobile/domain/models/log.model.dart';
import 'package:immich_mobile/i18n/strings.g.dart';
import 'package:immich_mobile/presentation/components/scaffold/adaptive_route_appbar.widget.dart';
import 'package:immich_mobile/presentation/theme/app_typography.dart';
import 'package:immich_mobile/utils/extensions/build_context.extension.dart';
import 'package:immich_mobile/utils/snackbar_manager.dart';
import 'package:material_symbols_icons/symbols.dart';
@RoutePage()
class LogDetailsPage extends StatelessWidget {
final LogMessage log;
const LogDetailsPage({super.key, required this.log});
String _getClipboardText() {
return """
Message: ${log.content}
Logged at: ${log.createdAt}
Context: ${log.logger ?? "<NA>"}
Error: ${log.error ?? "<NA>"}
Stack:
------
${log.stack ?? "<NA>"}
""";
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: ImAdaptiveRouteAppBar(
title: context.t.logs.detail.title,
isPrimary: false,
actions: [
IconButton(
onPressed: () => unawaited(
Clipboard.setData(ClipboardData(text: _getClipboardText()))
.then((_) {
if (context.mounted) {
SnackbarManager.showText(
content: context.t.common.copied_long,
);
}
}),
),
icon: Icon(
Symbols.copy_all_rounded,
color: context.colorScheme.primary,
),
),
],
),
body: SafeArea(
child: ListView(
children: [
_TextWithCopy(
heading: context.t.logs.detail.message_heading,
text: log.content,
),
Divider(),
if (log.logger != null) ...<Widget>[
_TextWithCopy(
heading: context.t.logs.detail.context_heading,
text: log.logger!.toString(),
),
Divider(),
],
if (log.error != null) ...<Widget>[
_TextWithCopy(
heading: context.t.logs.detail.error_heading,
text: log.error!.toString(),
),
Divider(),
],
if (log.stack != null) ...<Widget>[
_TextWithCopy(
heading: context.t.logs.detail.stack_heading,
text: log.stack!.toString(),
),
Divider(),
],
],
),
),
);
}
}
class _TextWithCopy extends StatelessWidget {
final String heading;
final String text;
const _TextWithCopy({required this.heading, required this.text});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left: 16.0, top: 16.0, bottom: 10.0),
child: Text(
heading,
style: AppTypography.bodyMedium.copyWith(
color: context.colorScheme.primary,
fontWeight: FontWeight.bold,
),
),
),
Padding(
padding: const EdgeInsets.only(left: 16.0, bottom: 10.0),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SelectableText(
text,
style: AppTypography.bodySmall,
textAlign: TextAlign.justify,
),
),
),
],
);
}
}

View File

@ -30,7 +30,6 @@ class LogsWrapperPage extends StatelessWidget {
return ImAdaptiveRouteWrapper(
primaryRoute: LogsRoute.name,
primaryBody: (_) => const LogsPage(),
bodyRatio: RatioConstants.oneThird,
);
}
}
@ -151,6 +150,7 @@ class _LogList extends StatelessWidget {
trailing: const Icon(Symbols.arrow_forward_ios_rounded, size: 18),
dense: true,
visualDensity: VisualDensity.compact,
onTap: () => unawaited(context.navigateTo(LogDetailsRoute(log: log))),
tileColor: _getTileColor(context, log.level),
minLeadingWidth: 10,
);

View File

@ -2,7 +2,7 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart';
import 'package:immich_mobile/i18n/strings.g.dart';
import 'package:immich_mobile/presentation/components/common/immich_navigation_rail.dart';
import 'package:immich_mobile/presentation/components/common/immich_navigation_rail.widget.dart';
import 'package:immich_mobile/presentation/components/common/user_avatar.widget.dart';
import 'package:immich_mobile/presentation/components/image/immich_logo.widget.dart';
import 'package:immich_mobile/presentation/router/router.dart';

View File

@ -1,7 +1,10 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:immich_mobile/domain/models/log.model.dart';
import 'package:immich_mobile/presentation/modules/home/pages/home.page.dart';
import 'package:immich_mobile/presentation/modules/library/pages/library.page.dart';
import 'package:immich_mobile/presentation/modules/login/pages/login.page.dart';
import 'package:immich_mobile/presentation/modules/logs/pages/log_details.page.dart';
import 'package:immich_mobile/presentation/modules/logs/pages/logs.page.dart';
import 'package:immich_mobile/presentation/modules/search/pages/search.page.dart';
import 'package:immich_mobile/presentation/modules/settings/pages/about_settings.page.dart';
@ -37,8 +40,8 @@ class AppRouter extends RootStackRouter {
),
AutoRoute(page: LogsWrapperRoute.page, children: [
AutoRoute(page: LogsRoute.page),
AutoRoute(page: LogDetailsRoute.page),
]),
AutoRoute(page: LogsRoute.page),
AutoRoute(page: TabControllerRoute.page, children: [
AutoRoute(page: HomeRoute.page),
AutoRoute(page: SearchRoute.page),

View File

@ -26,6 +26,7 @@ abstract final class AppColors {
surface: Color(0xFFF0EFF4),
onSurface: Color(0xff1a1b21),
surfaceContainer: Color(0xfffefbff),
surfaceContainerHigh: Color(0xFFE0E1EA),
surfaceContainerHighest: Color(0xffe0e2ef),
onSurfaceVariant: Color(0xff444651),
outline: Color(0xff747782),
@ -59,6 +60,7 @@ abstract final class AppColors {
surface: Color(0xFF15181C),
onSurface: Color(0xffe2e2e9),
surfaceContainer: Color(0xff1a1e22),
surfaceContainerHigh: Color(0xFF2C3138),
surfaceContainerHighest: Color(0xff424852),
onSurfaceVariant: Color(0xffc2c6d2),
outline: Color(0xff8c919c),

View File

@ -64,6 +64,7 @@ enum AppTheme {
closeButtonIconBuilder: (_) => Icon(Symbols.close_rounded),
),
appBarTheme: AppBarTheme(
backgroundColor: color.surfaceContainerLowest,
iconTheme: IconThemeData(size: 22, color: color.onSurface),
titleTextStyle:
AppTypography.titleLarge.copyWith(color: color.onSurface),

View File

@ -14,6 +14,8 @@ abstract final class SizeConstants {
abstract final class RatioConstants {
const RatioConstants._();
// 0.5
static const oneHalf = 1 / 2;
// 0.3
static const oneThird = 1 / 3;
// 0.25

View File

@ -10,4 +10,9 @@ abstract final class SnackbarManager {
_s?.clearSnackBars();
_s?.showSnackBar(SnackBar(content: Text(errorMsg)));
}
static void showText({required String content, TextStyle? style}) {
_s?.clearSnackBars();
_s?.showSnackBar(SnackBar(content: Text(content, style: style)));
}
}