Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lulin/task/add signin in chat page #71

Merged
merged 2 commits into from
Dec 5, 2024
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
58 changes: 25 additions & 33 deletions lib/app/injection_container.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,59 +35,51 @@ final sl = GetIt.instance;
void initInjection() {
// ViewModels
sl.registerFactory<ChatViewModel>(() => ChatViewModel(
chatUseCase: sl(), chatSessionUseCase: sl(), functionToolsUseCase: sl(), authUseCase: sl()));
chatUseCase: sl(),
chatSessionUseCase: sl(),
functionToolsUseCase: sl(),
authUseCase: sl(),
userUserCase: sl()));
sl.registerFactory<LoginViewModel>(
() => LoginViewModel(authUseCase: sl(), appleSignInService: sl(), googleSignInService: sl()));
sl.registerFactory<SignupViewModel>(() => SignupViewModel(authUseCase: sl()));
sl.registerFactory<SettingsViewModel>(() => SettingsViewModel(
authUseCase: sl(), userUserCase: sl(), featureFlagProvider: sl()));
sl.registerFactory<QASettingsViewModel>(() => QASettingsViewModel(
featureFlagProvider: sl(),
apiEnvironment: sl(),
authUseCase: sl()));
sl.registerFactory<SettingsViewModel>(
() => SettingsViewModel(authUseCase: sl(), userUserCase: sl(), featureFlagProvider: sl()));
sl.registerFactory<QASettingsViewModel>(() =>
QASettingsViewModel(featureFlagProvider: sl(), apiEnvironment: sl(), authUseCase: sl()));
sl.registerFactory<UserProfileViewModel>(
() => UserProfileViewModel(authUseCase: sl(), userUseCase: sl()));
sl.registerFactory<ForgetPasswordViewModel>(
() => ForgetPasswordViewModel(authUseCase: sl()));
sl.registerFactory<UpdatePasswordViewModel>(
() => UpdatePasswordViewModel(authUseCase: sl()));
sl.registerFactory<ForgetPasswordViewModel>(() => ForgetPasswordViewModel(authUseCase: sl()));
sl.registerFactory<UpdatePasswordViewModel>(() => UpdatePasswordViewModel(authUseCase: sl()));

// Use Cases
sl.registerLazySingleton<ChatUseCase>(
() => ChatUseCase(chatRepository: sl()));
sl.registerLazySingleton<ChatUseCase>(() => ChatUseCase(chatRepository: sl()));

sl.registerLazySingleton<ChatSessionUseCase>(
() => ChatSessionUseCase(repository: sl()));
sl.registerLazySingleton<ChatSessionUseCase>(() => ChatSessionUseCase(repository: sl()));

sl.registerLazySingleton<FunctionToolsUseCase>(() => FunctionToolsUseCase());

sl.registerLazySingleton<AuthUseCase>(
() => AuthUseCaseImpl(repository: sl(), tokenProvider: sl()));
sl.registerLazySingleton<UserUseCase>(
() => UserUseCase(repository: sl(), tokenProvider: sl()));
sl.registerLazySingleton<UserUseCase>(() => UserUseCase(repository: sl(), tokenProvider: sl()));

// Repositories
sl.registerLazySingleton<ChatRepository>(() =>
ChatRepositoryImp(openAIDataSource: sl(), functionToolsDataSource: sl()));
sl.registerLazySingleton<ChatSessionRepository>(
() => ChatSessionRepositoryImpl());
sl.registerLazySingleton<AuthRepository>(() => AuthRepositoryImpl(
client: sl(), authClient: sl(), apiEnvironment: sl()));
sl.registerLazySingleton<UserRepository>(() =>
UserRepositoryImpl(authClient: sl(), apiEnvironment: sl()));
sl.registerLazySingleton<ChatRepository>(
() => ChatRepositoryImp(openAIDataSource: sl(), functionToolsDataSource: sl()));
sl.registerLazySingleton<ChatSessionRepository>(() => ChatSessionRepositoryImpl());
sl.registerLazySingleton<AuthRepository>(
() => AuthRepositoryImpl(client: sl(), authClient: sl(), apiEnvironment: sl()));
sl.registerLazySingleton<UserRepository>(
() => UserRepositoryImpl(authClient: sl(), apiEnvironment: sl()));

// Data Sources
sl.registerLazySingleton<OpenAIDataSource>(
() => ChatRemoteDataSourceImpl(client: sl()));
sl.registerLazySingleton<FunctionToolsDataSource>(
() => FunctionToolsDataSourceImp());
sl.registerLazySingleton<OpenAIDataSource>(() => ChatRemoteDataSourceImpl(client: sl()));
sl.registerLazySingleton<FunctionToolsDataSource>(() => FunctionToolsDataSourceImp());

// Infrastructure
sl.registerLazySingleton(() => http.Client());
sl.registerLazySingleton<AuthenticatedHttpClient>(
() => AuthenticatedHttpClient(sl(), sl()));
sl.registerLazySingleton<APIEnvironment>(
() => APIEnvironment());
sl.registerLazySingleton<AuthenticatedHttpClient>(() => AuthenticatedHttpClient(sl(), sl()));
sl.registerLazySingleton<APIEnvironment>(() => APIEnvironment());
sl.registerLazySingleton<TokenProvider>(() => TokenProvider());
sl.registerLazySingleton<FeatureFlagProvider>(() => FeatureFlagProvider());
sl.registerLazySingleton<AppleSignInService>(() => AppleSignInServiceImpl());
Expand Down
63 changes: 53 additions & 10 deletions lib/presentation/chat/viewModels/chat_view_model.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import 'dart:async';
import 'package:domain/domain.dart';
import 'package:domain/entities/user.dart';
import 'package:domain/usecases/auth_usecase.dart';
import 'package:domain/usecases/function_tools_usecase.dart';
import 'package:domain/usecases/user_usercase.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';

class ChatViewModel extends ChangeNotifier {
final ChatUseCase _chatUseCase;
final ChatSessionUseCase _chatSessionUseCase;
final FunctionToolsUseCase _functionToolsUseCase;
final AuthUseCase _authUseCase;
final UserUseCase _userUserCase;

bool isLoggedIn = false;
User? user;

final ScrollController scrollController = ScrollController();
bool isLoading = false;
Expand All @@ -34,19 +39,55 @@ class ChatViewModel extends ChangeNotifier {
// "Give me some math equations.",
];

ChatViewModel(
{required ChatUseCase chatUseCase,
required ChatSessionUseCase chatSessionUseCase,
required FunctionToolsUseCase functionToolsUseCase,
required AuthUseCase authUseCase})
: _chatUseCase = chatUseCase,
ChatViewModel({
required ChatUseCase chatUseCase,
required ChatSessionUseCase chatSessionUseCase,
required FunctionToolsUseCase functionToolsUseCase,
required AuthUseCase authUseCase,
required UserUseCase userUserCase,
}) : _chatUseCase = chatUseCase,
_chatSessionUseCase = chatSessionUseCase,
_functionToolsUseCase = functionToolsUseCase,
_authUseCase = authUseCase{
_authUseCase = authUseCase,
_userUserCase = userUserCase {
checkAuthStatus();
initializeChatSessions();
}



Future<void> fetchAuthSessionNew() async {
try {
isLoggedIn = await _authUseCase.isLoggedIn();
if (isLoggedIn) {
await fetchUser();
} else {
user = null; // Ensure user is null if not logged in
}
} catch (e) {
if (kDebugMode) {
print(e);
}
isLoggedIn = false;
user = null; // Ensure proper reset
}
notifyListeners();
}

Future<void> fetchUser() async {
try {
user = await _userUserCase.fetchMe();
isLoggedIn = true; // Ensure isLoggedIn is updated correctly
} catch (e) {
if (kDebugMode) {
print(e);
}
isLoggedIn = false; // Handle fetch user failure
user = null;
}
notifyListeners();
}

@override
void dispose() {
scrollController.dispose();
Expand All @@ -68,9 +109,11 @@ class ChatViewModel extends ChangeNotifier {
Future<void> checkAuthStatus() async {
isLoggedIn = await _authUseCase.isLoggedIn();
print("isLoggedIn: $isLoggedIn");

// Temporarily set it to true for demonstration
isLoggedIn = true;
if (isLoggedIn) {
await fetchUser();
} else {
user = null; // Ensure user is null if not logged in
}
notifyListeners();
}

Expand Down
176 changes: 148 additions & 28 deletions lib/presentation/chat/views/chat_screen.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../../../app/injection_container.dart';
import '../../settings/views/login_page.dart';
import '../../settings/views/user_profile_page.dart';
import '../viewModels/chat_view_model.dart';
import 'chat_message_list.dart';
import 'chat_session_drawer.dart';

class ChatScreen extends StatefulWidget {
const ChatScreen({Key? key}) : super(key: key);

@override
State<ChatScreen> createState() => _ChatScreenState();
}
Expand All @@ -18,39 +20,157 @@ class _ChatScreenState extends State<ChatScreen>
@override
bool get wantKeepAlive => true;

late ChatViewModel viewModel;

@override
void initState() {
super.initState();
viewModel = Provider.of<ChatViewModel>(context, listen: false);
_fetchAuthSession();
}

Future<void> _fetchAuthSession() async {
await viewModel.fetchAuthSessionNew();
setState(() {});
}

@override
Widget build(BuildContext context) {
return Consumer<ChatViewModel>(builder: (context, viewModel, _) {
return Scaffold(
appBar: AppBar(title: const Text("Chat")),
drawer: (viewModel.isLoggedIn) ? ChatDrawer() : null,
body: (viewModel.isLoggedIn)
? ChatMessageList()
: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
"You need to be logged in to use the chat feature.",
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
ElevatedButton(
super.build(context); // Ensure AutomaticKeepAliveClientMixin works
return Consumer<ChatViewModel>(
builder: (context, viewModel, _) {
return Scaffold(
appBar: AppBar(
title: const Text("Chat"),
actions: [
Builder(
builder: (context) {
if (!viewModel.isLoggedIn) {
// If the user is not logged in, show login icon
return IconButton(
icon: const Icon(Icons.login),
color: Colors.white,
tooltip: "Sign In",
onPressed: () async {
String? result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const LoginPage()));
context,
MaterialPageRoute(builder: (context) => const LoginPage()),
);
if (result == "Log in Success") {
await viewModel.checkAuthStatus();
setState(() {}); // Trigger UI rebuild
}
},
child: const Text("Login to Chat"),
),
],
),
);
} else {
// If the user is logged in, show profile info
return Row(
mainAxisSize: MainAxisSize.min, // Keep it compact
children: [
GestureDetector(
onTap: () async {
String? result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UserProfilePage(),
),
);
if (result == "refresh") {
await viewModel.checkAuthStatus(); // Refresh the authentication status
setState(() {}); // Rebuild the UI
}
},
child: viewModel.user?.avatarUrl != null
? CircleAvatar(
backgroundImage: NetworkImage(viewModel.user!.avatarUrl!),
radius: 16, // Adjust radius to fit in the app bar
)
: const Icon(
Icons.account_circle,
size: 40,
color: Colors.white,
),
),
const SizedBox(width: 8),
],
);
}
},
),
);
});
],
),
drawer: viewModel.isLoggedIn ? ChatDrawer() : null,
body: Stack(
children: [
// Main content (ChatMessageList or Login prompt)
ChatMessageList(),

// Blur effect applied when the user is not logged in and there are more than 6 messages
if (!viewModel.isLoggedIn && viewModel.messages.length > 6)
BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), // Adjust blur intensity
child: Container(
color: Colors.black.withOpacity(0.2), // Semi-transparent overlay
),
),

// Foreground content (Text & Button) remains fully visible
if (!viewModel.isLoggedIn && viewModel.messages.length > 6)
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(
Icons.chat_bubble_outline,
size: 100,
color: Colors.blueAccent,
),
const SizedBox(height: 20),
const Text(
"Please sign in to access the chat and continue your learning experience.",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
color: Colors.black, // Keep text fully visible
),
),
const SizedBox(height: 30),
ElevatedButton.icon(
onPressed: () async {
String? result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const LoginPage(),
),
);
if (result == "Log in Success") {
await viewModel.checkAuthStatus();
setState(() {}); // Trigger UI rebuild
}
},
icon: const Icon(Icons.login, size: 20),
label: const Text(
"Login to Chat",
style: TextStyle(fontSize: 16),
),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
),
],
),
),
],
),


);
},
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class UserProfileViewModel extends ChangeNotifier {
print("Account deleted successfully");
} catch (e) {
_errorMessage = 'Delete failed: ${e.toString()}';
return null;

} finally {
setLoading(false);
}
Expand Down
Loading
Loading