Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
analyzer:
errors:
avoid_print: ignore
document_ignores: ignore
lines_longer_than_80_chars: ignore
include: package:very_good_analysis/analysis_options.9.0.0.yaml
linter:
rules:
Expand Down
11 changes: 4 additions & 7 deletions lib/app/bloc/app_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:ht_auth_repository/ht_auth_repository.dart';
import 'package:ht_data_repository/ht_data_repository.dart';
import 'package:ht_dashboard/app/config/config.dart' as local_config;
import 'package:ht_data_repository/ht_data_repository.dart';
import 'package:ht_shared/ht_shared.dart';

part 'app_event.dart';
Expand All @@ -21,11 +21,7 @@ class AppBloc extends Bloc<AppEvent, AppState> {
_appConfigRepository = appConfigRepository,
_environment = environment,
super(
const AppState(
user: null,
status: AppStatus.initial,
environment: null,
),
const AppState(),
) {
on<AppUserChanged>(_onAppUserChanged);
on<AppLogoutRequested>(_onLogoutRequested);
Expand Down Expand Up @@ -56,7 +52,8 @@ class AppBloc extends Bloc<AppEvent, AppState> {
status = AppStatus.authenticated;
// ignore: no_default_cases
default: // Fallback for any other roles not explicitly handled
status = AppStatus.unauthenticated; // Treat other roles as unauthenticated for dashboard
status = AppStatus
.unauthenticated; // Treat other roles as unauthenticated for dashboard
}

// Emit user and status update
Expand Down
8 changes: 4 additions & 4 deletions lib/app/bloc/app_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ class AppState extends Equatable {

@override
List<Object?> get props => [
status,
user,
environment,
];
status,
user,
environment,
];
}
13 changes: 6 additions & 7 deletions lib/app/view/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:ht_auth_repository/ht_auth_repository.dart';
import 'package:ht_data_repository/ht_data_repository.dart';
import 'package:ht_kv_storage_service/ht_kv_storage_service.dart';
import 'package:ht_dashboard/app/bloc/app_bloc.dart';
import 'package:ht_dashboard/app/config/app_environment.dart';
import 'package:ht_dashboard/authentication/bloc/authentication_bloc.dart';
import 'package:ht_dashboard/l10n/app_localizations.dart';
import 'package:ht_dashboard/l10n/l10n.dart';
import 'package:ht_dashboard/router/router.dart';
import 'package:ht_data_repository/ht_data_repository.dart';
import 'package:ht_kv_storage_service/ht_kv_storage_service.dart';
import 'package:ht_shared/ht_shared.dart';

class App extends StatelessWidget {
Expand All @@ -24,7 +23,7 @@ class App extends StatelessWidget {
required HtDataRepository<Source> htSourcesRepository,
required HtDataRepository<UserAppSettings> htUserAppSettingsRepository,
required HtDataRepository<UserContentPreferences>
htUserContentPreferencesRepository,
htUserContentPreferencesRepository,
required HtDataRepository<AppConfig> htAppConfigRepository,
required HtKVStorageService kvStorageService,
required AppEnvironment environment,
Expand All @@ -47,7 +46,7 @@ class App extends StatelessWidget {
final HtDataRepository<Source> _htSourcesRepository;
final HtDataRepository<UserAppSettings> _htUserAppSettingsRepository;
final HtDataRepository<UserContentPreferences>
_htUserContentPreferencesRepository;
_htUserContentPreferencesRepository;
final HtDataRepository<AppConfig> _htAppConfigRepository;
final HtKVStorageService _kvStorageService;
final AppEnvironment _environment;
Expand All @@ -71,8 +70,8 @@ class App extends StatelessWidget {
BlocProvider(
create: (context) => AppBloc(
authenticationRepository: context.read<HtAuthRepository>(),
userAppSettingsRepository:
context.read<HtDataRepository<UserAppSettings>>(),
userAppSettingsRepository: context
.read<HtDataRepository<UserAppSettings>>(),
appConfigRepository: context.read<HtDataRepository<AppConfig>>(),
environment: _environment,
),
Expand Down
1 change: 0 additions & 1 deletion lib/app/view/app_shell.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart';
import 'package:go_router/go_router.dart';
import 'package:ht_dashboard/l10n/l10n.dart';
import 'package:ht_dashboard/router/routes.dart';

/// A responsive scaffold shell for the main application sections.
///
Expand Down
99 changes: 99 additions & 0 deletions lib/app_configuration/bloc/app_configuration_bloc.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:ht_data_repository/ht_data_repository.dart';
import 'package:ht_shared/ht_shared.dart'; // Use AppConfig from ht_shared

part 'app_configuration_event.dart';
part 'app_configuration_state.dart';

class AppConfigurationBloc
extends Bloc<AppConfigurationEvent, AppConfigurationState> {
AppConfigurationBloc({
required HtDataRepository<AppConfig> appConfigRepository,
}) : _appConfigRepository = appConfigRepository,
super(const AppConfigurationState()) {
on<AppConfigurationLoaded>(_onAppConfigurationLoaded);
on<AppConfigurationUpdated>(_onAppConfigurationUpdated);
on<AppConfigurationFieldChanged>(_onAppConfigurationFieldChanged);
}

final HtDataRepository<AppConfig> _appConfigRepository;

Future<void> _onAppConfigurationLoaded(
AppConfigurationLoaded event,
Emitter<AppConfigurationState> emit,
) async {
emit(state.copyWith(status: AppConfigurationStatus.loading));
try {
final appConfig = await _appConfigRepository.read(id: 'app_config');
emit(
state.copyWith(
status: AppConfigurationStatus.success,
appConfig: appConfig,
isDirty: false,
),
);
} on HtHttpException catch (e) {
emit(
state.copyWith(
status: AppConfigurationStatus.failure,
errorMessage: e.message,
),
);
} catch (e) {
emit(
state.copyWith(
status: AppConfigurationStatus.failure,
errorMessage: 'An unknown error occurred: $e',
),
);
}
}

Future<void> _onAppConfigurationUpdated(
AppConfigurationUpdated event,
Emitter<AppConfigurationState> emit,
) async {
emit(state.copyWith(status: AppConfigurationStatus.loading));
try {
final updatedConfig = await _appConfigRepository.update(
id: event.appConfig.id,
item: event.appConfig,
);
emit(
state.copyWith(
status: AppConfigurationStatus.success,
appConfig: updatedConfig,
isDirty: false,
),
);
} on HtHttpException catch (e) {
emit(
state.copyWith(
status: AppConfigurationStatus.failure,
errorMessage: e.message,
),
);
} catch (e) {
emit(
state.copyWith(
status: AppConfigurationStatus.failure,
errorMessage: 'An unknown error occurred: $e',
),
);
}
}

void _onAppConfigurationFieldChanged(
AppConfigurationFieldChanged event,
Emitter<AppConfigurationState> emit,
) {
emit(
state.copyWith(
appConfig: event.appConfig,
isDirty: true,
clearErrorMessage: true, // Clear any previous error messages
),
);
}
}
53 changes: 53 additions & 0 deletions lib/app_configuration/bloc/app_configuration_event.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
part of 'app_configuration_bloc.dart';

/// Abstract base class for all events in the AppConfigurationBloc.
abstract class AppConfigurationEvent extends Equatable {
/// {@macro app_configuration_event}
const AppConfigurationEvent();

@override
List<Object?> get props => [];
}

/// {@template app_configuration_loaded}
/// Event to request the loading of the application configuration.
/// {@endtemplate}
class AppConfigurationLoaded extends AppConfigurationEvent {
/// {@macro app_configuration_loaded}
const AppConfigurationLoaded();
}

/// {@template app_configuration_updated}
/// Event to request the update of the application configuration.
///
/// Carries the new [appConfig] object to be saved.
/// {@endtemplate}
class AppConfigurationUpdated extends AppConfigurationEvent {
/// {@macro app_configuration_updated}
const AppConfigurationUpdated(this.appConfig);

/// The updated application configuration.
final AppConfig appConfig;

@override
List<Object?> get props => [appConfig];
}

/// {@template app_configuration_field_changed}
/// Event to notify that a field in the application configuration has changed.
///
/// This event is used to update the local state and mark it as dirty,
/// without immediately triggering a backend save.
/// {@endtemplate}
class AppConfigurationFieldChanged extends AppConfigurationEvent {
/// {@macro app_configuration_field_changed}
const AppConfigurationFieldChanged({
this.appConfig,
});

/// The partially or fully updated AppConfig object.
final AppConfig? appConfig;

@override
List<Object?> get props => [appConfig];
}
67 changes: 67 additions & 0 deletions lib/app_configuration/bloc/app_configuration_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
part of 'app_configuration_bloc.dart';

/// Represents the status of the AppConfigurationBloc.
enum AppConfigurationStatus {
/// The configuration is in its initial state.
initial,

/// The configuration is currently being loaded.
loading,

/// The configuration has been successfully loaded or updated.
success,

/// An error occurred during loading or updating the configuration.
failure,
}

/// {@template app_configuration_state}
/// State for the AppConfigurationBloc.
/// {@endtemplate}
class AppConfigurationState extends Equatable {
/// {@macro app_configuration_state}
const AppConfigurationState({
this.status = AppConfigurationStatus.initial,
this.appConfig,
this.errorMessage,
this.isDirty = false,
});

/// The current status of the application configuration.
final AppConfigurationStatus status;

/// The loaded or updated application configuration.
final AppConfig? appConfig;

/// An error message if an operation failed.
final String? errorMessage;

/// Indicates if there are unsaved changes to the configuration.
final bool isDirty;

/// Creates a copy of the current state with updated values.
AppConfigurationState copyWith({
AppConfigurationStatus? status,
AppConfig? appConfig,
String? errorMessage,
bool? isDirty,
bool clearErrorMessage = false,
}) {
return AppConfigurationState(
status: status ?? this.status,
appConfig: appConfig ?? this.appConfig,
errorMessage: clearErrorMessage
? null
: errorMessage ?? this.errorMessage,
isDirty: isDirty ?? this.isDirty,
);
}

@override
List<Object?> get props => [
status,
appConfig,
errorMessage,
isDirty,
];
}
Loading