diff --git a/lib/main.dart b/lib/main.dart index 044ae45..5a2d42f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,16 +8,15 @@ import 'package:logging/logging.dart'; import 'package:twonly/src/providers/download_change_provider.dart'; import 'package:twonly/src/providers/messages_change_provider.dart'; import 'package:twonly/src/providers/contacts_change_provider.dart'; +import 'package:twonly/src/providers/settings_change_provider.dart'; import 'package:twonly/src/utils/misc.dart'; import 'src/app.dart'; -import 'src/settings/settings_controller.dart'; -import 'src/settings/settings_service.dart'; late DbProvider dbProvider; late ApiProvider apiProvider; void main() async { - final settingsController = SettingsController(SettingsService()); + final settingsController = SettingsChangeProvider(); // Load the user's preferred theme while the splash screen is displayed. // This prevents a sudden theme change when the app is first displayed. @@ -62,8 +61,9 @@ void main() async { ChangeNotifierProvider(create: (_) => MessagesChangeProvider()), ChangeNotifierProvider(create: (_) => DownloadChangeProvider()), ChangeNotifierProvider(create: (_) => ContactChangeProvider()), + ChangeNotifierProvider(create: (_) => settingsController), ], - child: MyApp(settingsController: settingsController), + child: MyApp(), ), ); } diff --git a/lib/src/app.dart b/lib/src/app.dart index 6528509..d2352a1 100644 --- a/lib/src/app.dart +++ b/lib/src/app.dart @@ -3,6 +3,7 @@ import 'package:twonly/main.dart'; import 'package:twonly/src/providers/contacts_change_provider.dart'; import 'package:twonly/src/providers/download_change_provider.dart'; import 'package:twonly/src/providers/messages_change_provider.dart'; +import 'package:twonly/src/providers/settings_change_provider.dart'; import 'package:twonly/src/utils/storage.dart'; import 'package:twonly/src/views/onboarding_view.dart'; import 'package:twonly/src/views/home_view.dart'; @@ -11,7 +12,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'dart:async'; -import 'settings/settings_controller.dart'; // these global function can be called from anywhere to update // the ui when something changed. The callbacks will be set by @@ -27,9 +27,7 @@ Function(List, bool) globalCallBackOnDownloadChange = (a, b) {}; /// The Widget that configures your application. class MyApp extends StatefulWidget { - const MyApp({super.key, required this.settingsController}); - - final SettingsController settingsController; + const MyApp({super.key}); @override State createState() => _MyAppState(); @@ -114,7 +112,7 @@ class _MyAppState extends State { // The ListenableBuilder Widget listens to the SettingsController for changes. // Whenever the user updates their settings, the MaterialApp is rebuilt. return ListenableBuilder( - listenable: widget.settingsController, + listenable: context.watch(), builder: (BuildContext context, Widget? child) { return MaterialApp( restorationScopeId: 'app', @@ -141,7 +139,7 @@ class _MyAppState extends State { inputDecorationTheme: const InputDecorationTheme(border: OutlineInputBorder()), ), - themeMode: widget.settingsController.themeMode, + themeMode: context.watch().themeMode, home: Stack( children: [ FutureBuilder( @@ -149,9 +147,7 @@ class _MyAppState extends State { builder: (context, snapshot) { if (snapshot.hasData) { return snapshot.data! - ? HomeView( - settingsController: widget.settingsController, - ) + ? HomeView() : _showOnboarding ? OnboardingView( callbackOnSuccess: () { diff --git a/lib/src/settings/settings_controller.dart b/lib/src/providers/settings_change_provider.dart similarity index 75% rename from lib/src/settings/settings_controller.dart rename to lib/src/providers/settings_change_provider.dart index e32c0df..abbb613 100644 --- a/lib/src/settings/settings_controller.dart +++ b/lib/src/providers/settings_change_provider.dart @@ -1,17 +1,10 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:twonly/src/services/settings_service.dart'; -import 'settings_service.dart'; - -/// A class that many Widgets can interact with to read user settings, update -/// user settings, or listen to user settings changes. -/// -/// Controllers glue Data Services to Flutter Widgets. The SettingsController -/// uses the SettingsService to store and retrieve user settings. -class SettingsController with ChangeNotifier { - SettingsController(this._settingsService); - +class SettingsChangeProvider with ChangeNotifier, DiagnosticableTreeMixin { // Make SettingsService a private variable so it is not used directly. - final SettingsService _settingsService; + final SettingsService _settingsService = SettingsService(); // Make ThemeMode a private variable so it is not updated directly without // also persisting the changes with the SettingsService. diff --git a/lib/src/settings/settings_service.dart b/lib/src/services/settings_service.dart similarity index 100% rename from lib/src/settings/settings_service.dart rename to lib/src/services/settings_service.dart diff --git a/lib/src/settings/settings_view.dart b/lib/src/settings/settings_view.dart deleted file mode 100644 index 435dd0c..0000000 --- a/lib/src/settings/settings_view.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'settings_controller.dart'; - -/// Displays the various settings that can be customized by the user. -/// -/// When a user changes a setting, the SettingsController is updated and -/// Widgets that listen to the SettingsController are rebuilt. -class SettingsView extends StatelessWidget { - const SettingsView({required this.controller}); - - final SettingsController controller; - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: const Text('Settings'), - ), - body: Column( - children: [ - Padding( - padding: const EdgeInsets.all(16), - // Glue the SettingsController to the theme selection DropdownButton. - // - // When a user selects a theme from the dropdown list, the - // SettingsController is updated, which rebuilds the MaterialApp. - child: DropdownButton( - // Read the selected themeMode from the controller - value: controller.themeMode, - // Call the updateThemeMode method any time the user selects a theme. - onChanged: controller.updateThemeMode, - items: const [ - DropdownMenuItem( - value: ThemeMode.system, - child: Text('System Theme'), - ), - DropdownMenuItem( - value: ThemeMode.light, - child: Text('Light Theme'), - ), - DropdownMenuItem( - value: ThemeMode.dark, - child: Text('Dark Theme'), - ) - ], - ), - ), - ElevatedButton( - onPressed: () { - showLicensePage(context: context); - }, - child: Text('Show Licenses'), - ), - ], - )); - } -} diff --git a/lib/src/views/chat_list_view.dart b/lib/src/views/chat_list_view.dart index af03d35..19d030c 100644 --- a/lib/src/views/chat_list_view.dart +++ b/lib/src/views/chat_list_view.dart @@ -1,3 +1,4 @@ +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:provider/provider.dart'; import 'package:twonly/src/components/flame.dart'; import 'package:twonly/src/components/initialsavatar.dart'; @@ -14,6 +15,7 @@ import 'package:twonly/src/utils/misc.dart'; import 'package:twonly/src/views/chat_item_details_view.dart'; import 'package:twonly/src/views/home_view.dart'; import 'package:twonly/src/views/media_viewer_view.dart'; +import 'package:twonly/src/views/profile_view.dart'; import 'package:twonly/src/views/search_username_view.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter/material.dart'; @@ -70,12 +72,23 @@ class _ChatListViewState extends State { return Scaffold( appBar: AppBar( - title: Text(AppLocalizations.of(context)!.chatsTitle), + title: GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ProfileView(), + ), + ); + }, + child: Text("twonly"), + ), + // title: actions: [ NotificationBadge( count: context.watch().newContactRequests, child: IconButton( - icon: Icon(Icons.person_add), + icon: FaIcon(FontAwesomeIcons.userPlus, size: 18), onPressed: () { Navigator.push( context, @@ -85,6 +98,17 @@ class _ChatListViewState extends State { ); }, ), + ), + IconButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ProfileView(), + ), + ); + }, + icon: FaIcon(FontAwesomeIcons.gear, size: 19), ) ], ), diff --git a/lib/src/views/home_view.dart b/lib/src/views/home_view.dart index b0edd13..21ae353 100644 --- a/lib/src/views/home_view.dart +++ b/lib/src/views/home_view.dart @@ -2,15 +2,12 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:pie_menu/pie_menu.dart'; import 'camera_preview_view.dart'; import 'chat_list_view.dart'; -import 'profile_view.dart'; -import '../settings/settings_controller.dart'; import 'package:flutter/material.dart'; Function(int) globalUpdateOfHomeViewPageIndex = (a) {}; class HomeView extends StatefulWidget { - const HomeView({super.key, required this.settingsController}); - final SettingsController settingsController; + const HomeView({super.key}); @override State createState() => HomeViewState(); @@ -71,7 +68,7 @@ class HomeViewState extends State { children: [ ChatListView(), CameraPreviewViewPermission(), - ProfileView(settingsController: widget.settingsController) + // ProfileView(settingsController: widget.settingsController) ], ), bottomNavigationBar: BottomNavigationBar( @@ -86,8 +83,8 @@ class HomeViewState extends State { icon: FaIcon(FontAwesomeIcons.camera), label: "", ), - BottomNavigationBarItem( - icon: FaIcon(FontAwesomeIcons.userShield), label: ""), + // BottomNavigationBarItem( + // icon: FaIcon(FontAwesomeIcons.userShield), label: ""), ], onTap: (int index) { activePageIdx = index; diff --git a/lib/src/views/profile_view.dart b/lib/src/views/profile_view.dart index c452df1..5611bdc 100644 --- a/lib/src/views/profile_view.dart +++ b/lib/src/views/profile_view.dart @@ -1,14 +1,14 @@ +import 'package:provider/provider.dart'; import 'package:twonly/src/model/json/user_data.dart'; import 'package:restart_app/restart_app.dart'; import 'package:flutter/material.dart'; -import 'package:twonly/src/settings/settings_controller.dart'; -import 'package:twonly/src/settings/settings_view.dart'; +import 'package:twonly/src/providers/settings_change_provider.dart'; import 'package:twonly/src/utils/storage.dart'; class ProfileView extends StatefulWidget { - const ProfileView({super.key, required this.settingsController}); + const ProfileView({super.key}); - final SettingsController settingsController; + // final SettingsController settingsController; @override State createState() => _ProfileViewState(); @@ -20,42 +20,68 @@ class _ProfileViewState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( + appBar: AppBar( title: FutureBuilder( - future: _userData, - builder: (context, snap) { - if (snap.hasData) { - return Text("Hello ${snap.data!.username}!"); - } else { - return Container(); - } - }), - actions: [ - IconButton( - icon: const Icon(Icons.settings), + future: _userData, + builder: (context, snap) { + if (snap.hasData) { + return Text("Settings"); + // return Text("Hello ${snap.data!.username}!"); + } else { + return Container(); + } + }, + ), + ), + body: Column( + children: [ + Padding( + padding: const EdgeInsets.all(16), + // Glue the SettingsController to the theme selection DropdownButton. + // + // When a user selects a theme from the dropdown list, the + // SettingsController is updated, which rebuilds the MaterialApp. + child: DropdownButton( + // Read the selected themeMode from the controller + value: context.watch().themeMode, + // Call the updateThemeMode method any time the user selects a theme. + onChanged: (theme) { + context.read().updateThemeMode(theme); + }, + items: const [ + DropdownMenuItem( + value: ThemeMode.system, + child: Text('System Theme'), + ), + DropdownMenuItem( + value: ThemeMode.light, + child: Text('Light Theme'), + ), + DropdownMenuItem( + value: ThemeMode.dark, + child: Text('Dark Theme'), + ) + ], + ), + ), + ElevatedButton( onPressed: () { - // Navigate to the settings page. If the user leaves and returns - // to the app after it has been killed while running in the - // background, the navigation stack is restored. - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - SettingsView(controller: widget.settingsController)), + showLicensePage(context: context); + }, + child: Text('Show Licenses'), + ), + FilledButton.icon( + onPressed: () async { + await deleteLocalUserData(); + Restart.restartApp( + notificationTitle: 'Successfully logged out', + notificationBody: 'Click here to open the app again', ); }, + label: Text("Logout"), + icon: Icon(Icons.no_accounts), ), - ]), - body: FilledButton.icon( - onPressed: () async { - await deleteLocalUserData(); - Restart.restartApp( - notificationTitle: 'Successfully logged out', - notificationBody: 'Click here to open the app again', - ); - }, - label: Text("Logout"), - icon: Icon(Icons.no_accounts)), - ); + ], + )); } }