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

Refactor: Decouple ViewModel by Moving UI Logic to View #2306

Merged
merged 4 commits into from
Jan 6, 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
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
import 'package:flutter/material.dart';
import 'package:talawa/enums/enums.dart';
import 'package:talawa/locator.dart';
import 'package:talawa/services/navigation_service.dart';
import 'package:talawa/view_model/base_view_model.dart';
import 'package:talawa/widgets/custom_alert_dialog.dart';
import 'package:talawa/widgets/talawa_error_dialog.dart';
import 'package:url_launcher/url_launcher_string.dart';

/// ViewModel for the App Settings functionality.
///
/// This ViewModel handles the logic and data for the application settings.
class AppSettingViewModel extends BaseModel {
// Services
final _navigationService = locator<NavigationService>();
// final _appLanguageService = locator<AppLanguage>();

/// This method destroys the user's session or sign out the user from app, The function asks for the confimation in Custom Alert Dialog.
Expand All @@ -22,9 +15,9 @@ class AppSettingViewModel extends BaseModel {
///
/// **returns**:
/// * `Future<void>`: Resolves when user logout
Future<void> logout(BuildContext context) async {
Future<void> logout() async {
// push custom alert dialog with the confirmation message.
_navigationService.pushDialog(logoutDialog());
await userConfig.userLogOut();
}

/// Launches a website using the provided URL.
Expand All @@ -36,41 +29,4 @@ class AppSettingViewModel extends BaseModel {
/// * `Future<bool>`: A [Future] that resolves to a [bool] value indicating
/// whether the website launch was successful.
Future<bool> launchWebsite(String url) async => await launchUrlString(url);

/// Creates a custom alert dialog for the logout confirmation.
///
/// This dialog prompts the user with a confirmation message for logout.
/// The dialog provides options to logout or cancel the operation.
///
/// **params**:
/// None
///
/// **returns**:
/// * `Widget`: A [Widget] representing the custom logout confirmation dialog.
Widget logoutDialog() {
return CustomAlertDialog(
reverse: true,
dialogSubTitle: 'Are you sure you want to logout?',
successText: 'Logout',
success: () async {
await userConfig.userLogOut();
navigationService.pop();
if (userConfig.loggedIn) {
navigationService.pushDialog(
const TalawaErrorDialog(
'Unable to logout, please try again.',
key: Key('TalawaError'),
messageType: MessageType.error,
),
);
} else {
navigationService.removeAllAndPush(
'/selectLang',
'/',
arguments: '0',
);
}
},
);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import 'package:flutter/material.dart';
import 'package:talawa/constants/routing_constants.dart';
import 'package:talawa/enums/enums.dart';
import 'package:talawa/locator.dart';
import 'package:talawa/services/size_config.dart';
import 'package:talawa/utils/app_localization.dart';
import 'package:talawa/view_model/after_auth_view_models/settings_view_models/app_setting_view_model.dart';
import 'package:talawa/views/base_view.dart';
import 'package:talawa/widgets/custom_alert_dialog.dart';
import 'package:talawa/widgets/lang_switch.dart';
import 'package:talawa/widgets/talawa_error_dialog.dart';
import 'package:talawa/widgets/theme_switch.dart';

/// Widget representing the App Settings page.
Expand Down Expand Up @@ -262,6 +265,7 @@ class AppSettingsPage extends StatelessWidget {
children: [
customDivider(context: context),
TextButton(
key: const Key('Logout'),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
Expand Down Expand Up @@ -289,7 +293,34 @@ class AppSettingsPage extends StatelessWidget {
),
onPressed: () {
userConfig.loggedIn
? model.logout(context)
? showDialog(
context: context,
builder: (context) {
return CustomAlertDialog(
reverse: true,
dialogSubTitle: 'Are you sure you want to logout?',
successText: 'LogOut',
success: () async {
try {
await model.logout();
navigationService.pop();
navigationService.removeAllAndPush(
'/selectLang',
'/',
);
} catch (e) {
navigationService.pushDialog(
const TalawaErrorDialog(
'Unable to logout, please try again.',
key: Key('TalawaError'),
messageType: MessageType.error,
),
);
}
},
);
},
)
: navigationService.pushScreen(
Routes.setUrlScreen,
arguments: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,17 @@

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:hive/hive.dart';
import 'package:mockito/mockito.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'package:talawa/models/organization/org_info.dart';
import 'package:talawa/models/user/user_info.dart';
import 'package:talawa/router.dart' as router;
import 'package:talawa/services/size_config.dart';
import 'package:talawa/utils/app_localization.dart';
import 'package:talawa/view_model/after_auth_view_models/settings_view_models/app_setting_view_model.dart';
import 'package:talawa/view_model/lang_view_model.dart';
import 'package:talawa/views/base_view.dart';
import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart';
import '../../../helpers/test_helpers.dart';
import '../../../helpers/test_locator.dart';
import '../../../router_test.dart';

class MockUrlLauncher extends Mock
with MockPlatformInterfaceMixin
Expand Down Expand Up @@ -64,74 +57,7 @@ void main() async {

test('Test logout function.', () {
final model = AppSettingViewModel();
final context = MockBuildContext();
model.logout(context);
});

testWidgets("Test logout dialog when logout successful.", (tester) async {
const userLoggedin = false;
when(userConfig.loggedIn).thenAnswer((_) => userLoggedin);
final model = AppSettingViewModel();

final widget = BaseView<AppLanguage>(
onModelReady: (model) => model.initialize(),
builder: (context, langModel, child) {
return MaterialApp(
locale: const Locale('en'),
localizationsDelegates: [
const AppLocalizationsDelegate(isTest: true),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
home: Scaffold(
body: model.logoutDialog(),
),
navigatorKey: navigationService.navigatorKey,
onGenerateRoute: router.generateRoute,
);
},
);

await tester.pumpWidget(widget);
await tester.pumpAndSettle();

await tester.tap(find.textContaining('Logout'));
await tester.pumpAndSettle();

verify(navigationService.navigatorKey);
});

testWidgets("Test logout dialog when logout unsuccessful.", (tester) async {
final model = AppSettingViewModel();
const userLoggedIn = true;
when(userConfig.loggedIn).thenAnswer((_) => userLoggedIn);

final widget = BaseView<AppLanguage>(
onModelReady: (model) => model.initialize(),
builder: (context, langModel, child) {
return MaterialApp(
locale: const Locale('en'),
localizationsDelegates: [
const AppLocalizationsDelegate(isTest: true),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
home: Scaffold(
body: model.logoutDialog(),
),
navigatorKey: navigationService.navigatorKey,
onGenerateRoute: router.generateRoute,
);
},
);

await tester.pumpWidget(widget);
await tester.pumpAndSettle();

await tester.tap(find.textContaining('Logout'));
await tester.pumpAndSettle();

verify(navigationService.navigatorKey);
model.logout();
});

test('test for launchWebsite method', () async {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import 'package:talawa/services/graphql_config.dart';
import 'package:talawa/services/navigation_service.dart';
import 'package:talawa/services/size_config.dart';
import 'package:talawa/utils/app_localization.dart';
import 'package:talawa/view_model/after_auth_view_models/settings_view_models/app_setting_view_model.dart';
import 'package:talawa/view_model/lang_view_model.dart';
import 'package:talawa/view_model/theme_view_model.dart';
import 'package:talawa/views/after_auth_screens/app_settings/app_settings_page.dart';
Expand Down Expand Up @@ -271,7 +272,10 @@ Future<void> main() async {
await tester.pumpWidget(createChangePassScreenDark());
await tester.pumpAndSettle();

final logoutButton = find.textContaining('Logout');
await tester.tap(find.byKey(const Key('Logout')));
await tester.pumpAndSettle();

final logoutButton = find.textContaining('LogOut');
await tester.tap(logoutButton);

unregisterServices();
Expand All @@ -288,5 +292,21 @@ Future<void> main() async {

verify(navigationService.navigatorKey);
});
testWidgets('Test if Logout is unsuccessful.', (tester) async {
final model = AppSettingViewModel();
when(model.logout()).thenThrow(Exception('Test error'));

const userLoggedIn = true;
when(userConfig.loggedIn).thenAnswer((_) => userLoggedIn);

await tester.pumpWidget(createChangePassScreenDark());
await tester.pumpAndSettle();

await tester.tap(find.byKey(const Key('Logout')));
await tester.pumpAndSettle();

final logoutButton = find.textContaining('LogOut');
await tester.tap(logoutButton);
});
});
}
Loading