nostr images fetching from API
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../home/home_screen.dart';
|
||||
import '../immich/immich_screen.dart';
|
||||
import '../nostr_events/nostr_events_screen.dart';
|
||||
import '../relay_management/relay_management_screen.dart';
|
||||
import '../relay_management/relay_management_controller.dart';
|
||||
import '../session/session_screen.dart';
|
||||
import '../settings/settings_screen.dart';
|
||||
import '../../data/nostr/nostr_service.dart';
|
||||
import '../../data/sync/sync_engine.dart';
|
||||
import '../../data/session/session_service.dart';
|
||||
import '../../data/local/local_storage_service.dart';
|
||||
import '../../data/firebase/firebase_service.dart';
|
||||
|
||||
/// Route names for the app navigation.
|
||||
class AppRoutes {
|
||||
static const String home = '/';
|
||||
static const String immich = '/immich';
|
||||
static const String nostrEvents = '/nostr-events';
|
||||
static const String relayManagement = '/relay-management';
|
||||
static const String session = '/session';
|
||||
static const String settings = '/settings';
|
||||
static const String login = '/login';
|
||||
}
|
||||
|
||||
/// Route guard that requires authentication.
|
||||
class AuthGuard {
|
||||
final SessionService? sessionService;
|
||||
|
||||
AuthGuard(this.sessionService);
|
||||
|
||||
/// Checks if user is authenticated.
|
||||
bool get isAuthenticated => sessionService?.isLoggedIn ?? false;
|
||||
|
||||
/// Redirects to login if not authenticated.
|
||||
String? checkAuth(String route) {
|
||||
if (_requiresAuth(route) && !isAuthenticated) {
|
||||
return AppRoutes.login;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Checks if a route requires authentication.
|
||||
bool _requiresAuth(String route) {
|
||||
// Routes that require authentication
|
||||
const protectedRoutes = [
|
||||
AppRoutes.immich,
|
||||
AppRoutes.nostrEvents,
|
||||
AppRoutes.session,
|
||||
];
|
||||
return protectedRoutes.contains(route);
|
||||
}
|
||||
}
|
||||
|
||||
/// App router for managing navigation and route guards.
|
||||
class AppRouter {
|
||||
final SessionService? sessionService;
|
||||
final LocalStorageService? localStorageService;
|
||||
final NostrService? nostrService;
|
||||
final SyncEngine? syncEngine;
|
||||
final FirebaseService? firebaseService;
|
||||
|
||||
late final AuthGuard _authGuard;
|
||||
|
||||
AppRouter({
|
||||
this.sessionService,
|
||||
this.localStorageService,
|
||||
this.nostrService,
|
||||
this.syncEngine,
|
||||
this.firebaseService,
|
||||
}) {
|
||||
_authGuard = AuthGuard(sessionService);
|
||||
}
|
||||
|
||||
/// Generates routes for the app.
|
||||
Route<dynamic>? generateRoute(RouteSettings settings) {
|
||||
// Check route guard
|
||||
final redirect = _authGuard.checkAuth(settings.name ?? '');
|
||||
if (redirect != null) {
|
||||
return MaterialPageRoute(
|
||||
builder: (_) => _buildLoginScreen(),
|
||||
settings: settings,
|
||||
);
|
||||
}
|
||||
|
||||
switch (settings.name) {
|
||||
case AppRoutes.home:
|
||||
return MaterialPageRoute(
|
||||
builder: (_) => HomeScreen(
|
||||
localStorageService: localStorageService,
|
||||
),
|
||||
settings: settings,
|
||||
);
|
||||
|
||||
case AppRoutes.immich:
|
||||
return MaterialPageRoute(
|
||||
builder: (_) => ImmichScreen(
|
||||
localStorageService: localStorageService,
|
||||
),
|
||||
settings: settings,
|
||||
);
|
||||
|
||||
case AppRoutes.nostrEvents:
|
||||
return MaterialPageRoute(
|
||||
builder: (_) => NostrEventsScreen(
|
||||
nostrService: nostrService,
|
||||
syncEngine: syncEngine,
|
||||
),
|
||||
settings: settings,
|
||||
);
|
||||
|
||||
case AppRoutes.relayManagement:
|
||||
if (nostrService == null || syncEngine == null) {
|
||||
return MaterialPageRoute(
|
||||
builder: (_) => _buildErrorScreen('Nostr service not available'),
|
||||
settings: settings,
|
||||
);
|
||||
}
|
||||
return MaterialPageRoute(
|
||||
builder: (_) => RelayManagementScreen(
|
||||
controller: RelayManagementController(
|
||||
nostrService: nostrService!,
|
||||
syncEngine: syncEngine!,
|
||||
),
|
||||
),
|
||||
settings: settings,
|
||||
);
|
||||
|
||||
case AppRoutes.session:
|
||||
return MaterialPageRoute(
|
||||
builder: (_) => SessionScreen(
|
||||
sessionService: sessionService,
|
||||
firebaseService: firebaseService,
|
||||
),
|
||||
settings: settings,
|
||||
);
|
||||
|
||||
case AppRoutes.settings:
|
||||
return MaterialPageRoute(
|
||||
builder: (_) => SettingsScreen(
|
||||
firebaseService: firebaseService,
|
||||
),
|
||||
settings: settings,
|
||||
);
|
||||
|
||||
case AppRoutes.login:
|
||||
return MaterialPageRoute(
|
||||
builder: (_) => _buildLoginScreen(),
|
||||
settings: settings,
|
||||
);
|
||||
|
||||
default:
|
||||
return MaterialPageRoute(
|
||||
builder: (_) => _buildErrorScreen('Route not found: ${settings.name}'),
|
||||
settings: settings,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildLoginScreen() {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Login Required'),
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.lock_outline,
|
||||
size: 64,
|
||||
color: Colors.grey,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'Please login to access this feature',
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
// Navigation will be handled by the navigation scaffold
|
||||
},
|
||||
child: const Text('Go to Login'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildErrorScreen(String message) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Error'),
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.error_outline,
|
||||
size: 64,
|
||||
color: Colors.red,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
message,
|
||||
style: const TextStyle(fontSize: 16),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../home/home_screen.dart';
|
||||
import '../immich/immich_screen.dart';
|
||||
import '../nostr_events/nostr_events_screen.dart';
|
||||
import '../session/session_screen.dart';
|
||||
import '../settings/settings_screen.dart';
|
||||
import '../../data/session/session_service.dart';
|
||||
import '../../data/local/local_storage_service.dart';
|
||||
import '../../data/nostr/nostr_service.dart';
|
||||
import '../../data/sync/sync_engine.dart';
|
||||
import '../../data/firebase/firebase_service.dart';
|
||||
import '../../data/immich/immich_service.dart';
|
||||
|
||||
/// Main navigation scaffold with bottom navigation bar.
|
||||
class MainNavigationScaffold extends StatefulWidget {
|
||||
final SessionService? sessionService;
|
||||
final LocalStorageService? localStorageService;
|
||||
final NostrService? nostrService;
|
||||
final SyncEngine? syncEngine;
|
||||
final FirebaseService? firebaseService;
|
||||
final ImmichService? immichService;
|
||||
|
||||
const MainNavigationScaffold({
|
||||
super.key,
|
||||
this.sessionService,
|
||||
this.localStorageService,
|
||||
this.nostrService,
|
||||
this.syncEngine,
|
||||
this.firebaseService,
|
||||
this.immichService,
|
||||
});
|
||||
|
||||
@override
|
||||
State<MainNavigationScaffold> createState() => _MainNavigationScaffoldState();
|
||||
}
|
||||
|
||||
class _MainNavigationScaffoldState extends State<MainNavigationScaffold> {
|
||||
int _currentIndex = 0;
|
||||
int _loginStateVersion = 0; // Increment when login state changes
|
||||
int? _pendingProtectedRoute; // Track if user was trying to access a protected route
|
||||
|
||||
void _onItemTapped(int index) {
|
||||
setState(() {
|
||||
_currentIndex = index;
|
||||
// If accessing a protected route (Immich=1, Nostr=2) while not logged in, remember it
|
||||
if ((index == 1 || index == 2) && !(widget.sessionService?.isLoggedIn ?? false)) {
|
||||
_pendingProtectedRoute = index;
|
||||
} else {
|
||||
_pendingProtectedRoute = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Callback to notify that login state may have changed
|
||||
void _onSessionStateChanged() {
|
||||
setState(() {
|
||||
_loginStateVersion++; // Force rebuild when login state changes
|
||||
|
||||
// If user just logged in and was trying to access a protected route, navigate there
|
||||
if (widget.sessionService?.isLoggedIn == true && _pendingProtectedRoute != null) {
|
||||
_currentIndex = _pendingProtectedRoute!;
|
||||
_pendingProtectedRoute = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildScreen(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return HomeScreen(
|
||||
localStorageService: widget.localStorageService,
|
||||
);
|
||||
case 1:
|
||||
// Check auth guard for Immich
|
||||
if (!(widget.sessionService?.isLoggedIn ?? false)) {
|
||||
return _buildLoginRequiredScreen();
|
||||
}
|
||||
return ImmichScreen(
|
||||
localStorageService: widget.localStorageService,
|
||||
immichService: widget.immichService,
|
||||
);
|
||||
case 2:
|
||||
// Check auth guard for Nostr Events
|
||||
if (!(widget.sessionService?.isLoggedIn ?? false)) {
|
||||
return _buildLoginRequiredScreen();
|
||||
}
|
||||
return NostrEventsScreen(
|
||||
nostrService: widget.nostrService,
|
||||
syncEngine: widget.syncEngine,
|
||||
);
|
||||
case 3:
|
||||
return SessionScreen(
|
||||
sessionService: widget.sessionService,
|
||||
firebaseService: widget.firebaseService,
|
||||
onSessionChanged: _onSessionStateChanged,
|
||||
);
|
||||
case 4:
|
||||
return SettingsScreen(
|
||||
firebaseService: widget.firebaseService,
|
||||
nostrService: widget.nostrService,
|
||||
syncEngine: widget.syncEngine,
|
||||
);
|
||||
default:
|
||||
return const SizedBox();
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildLoginRequiredScreen() {
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.lock_outline,
|
||||
size: 64,
|
||||
color: Colors.grey,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'Please login to access this feature',
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_currentIndex = 3; // Navigate to Session tab
|
||||
});
|
||||
},
|
||||
child: const Text('Go to Login'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Use login state version to force IndexedStack rebuild when login changes
|
||||
return Scaffold(
|
||||
body: IndexedStack(
|
||||
key: ValueKey('nav_$_currentIndex\_v$_loginStateVersion'),
|
||||
index: _currentIndex,
|
||||
children: List.generate(5, (index) => _buildScreen(index)),
|
||||
),
|
||||
bottomNavigationBar: BottomNavigationBar(
|
||||
type: BottomNavigationBarType.fixed,
|
||||
currentIndex: _currentIndex,
|
||||
onTap: _onItemTapped,
|
||||
items: const [
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.home),
|
||||
label: 'Home',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.photo_library),
|
||||
label: 'Immich',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.cloud),
|
||||
label: 'Nostr',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.person),
|
||||
label: 'Session',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: Icon(Icons.settings),
|
||||
label: 'Settings',
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user