mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 16:08:40 +00:00
improve settings view
This commit is contained in:
parent
d13de25f96
commit
6a342380b3
8 changed files with 105 additions and 127 deletions
|
|
@ -8,16 +8,15 @@ import 'package:logging/logging.dart';
|
||||||
import 'package:twonly/src/providers/download_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/messages_change_provider.dart';
|
||||||
import 'package:twonly/src/providers/contacts_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 'package:twonly/src/utils/misc.dart';
|
||||||
import 'src/app.dart';
|
import 'src/app.dart';
|
||||||
import 'src/settings/settings_controller.dart';
|
|
||||||
import 'src/settings/settings_service.dart';
|
|
||||||
|
|
||||||
late DbProvider dbProvider;
|
late DbProvider dbProvider;
|
||||||
late ApiProvider apiProvider;
|
late ApiProvider apiProvider;
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
final settingsController = SettingsController(SettingsService());
|
final settingsController = SettingsChangeProvider();
|
||||||
|
|
||||||
// Load the user's preferred theme while the splash screen is displayed.
|
// Load the user's preferred theme while the splash screen is displayed.
|
||||||
// This prevents a sudden theme change when the app is first 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: (_) => MessagesChangeProvider()),
|
||||||
ChangeNotifierProvider(create: (_) => DownloadChangeProvider()),
|
ChangeNotifierProvider(create: (_) => DownloadChangeProvider()),
|
||||||
ChangeNotifierProvider(create: (_) => ContactChangeProvider()),
|
ChangeNotifierProvider(create: (_) => ContactChangeProvider()),
|
||||||
|
ChangeNotifierProvider(create: (_) => settingsController),
|
||||||
],
|
],
|
||||||
child: MyApp(settingsController: settingsController),
|
child: MyApp(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import 'package:twonly/main.dart';
|
||||||
import 'package:twonly/src/providers/contacts_change_provider.dart';
|
import 'package:twonly/src/providers/contacts_change_provider.dart';
|
||||||
import 'package:twonly/src/providers/download_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/messages_change_provider.dart';
|
||||||
|
import 'package:twonly/src/providers/settings_change_provider.dart';
|
||||||
import 'package:twonly/src/utils/storage.dart';
|
import 'package:twonly/src/utils/storage.dart';
|
||||||
import 'package:twonly/src/views/onboarding_view.dart';
|
import 'package:twonly/src/views/onboarding_view.dart';
|
||||||
import 'package:twonly/src/views/home_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_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'settings/settings_controller.dart';
|
|
||||||
|
|
||||||
// these global function can be called from anywhere to update
|
// these global function can be called from anywhere to update
|
||||||
// the ui when something changed. The callbacks will be set by
|
// the ui when something changed. The callbacks will be set by
|
||||||
|
|
@ -27,9 +27,7 @@ Function(List<int>, bool) globalCallBackOnDownloadChange = (a, b) {};
|
||||||
|
|
||||||
/// The Widget that configures your application.
|
/// The Widget that configures your application.
|
||||||
class MyApp extends StatefulWidget {
|
class MyApp extends StatefulWidget {
|
||||||
const MyApp({super.key, required this.settingsController});
|
const MyApp({super.key});
|
||||||
|
|
||||||
final SettingsController settingsController;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<MyApp> createState() => _MyAppState();
|
State<MyApp> createState() => _MyAppState();
|
||||||
|
|
@ -114,7 +112,7 @@ class _MyAppState extends State<MyApp> {
|
||||||
// The ListenableBuilder Widget listens to the SettingsController for changes.
|
// The ListenableBuilder Widget listens to the SettingsController for changes.
|
||||||
// Whenever the user updates their settings, the MaterialApp is rebuilt.
|
// Whenever the user updates their settings, the MaterialApp is rebuilt.
|
||||||
return ListenableBuilder(
|
return ListenableBuilder(
|
||||||
listenable: widget.settingsController,
|
listenable: context.watch<SettingsChangeProvider>(),
|
||||||
builder: (BuildContext context, Widget? child) {
|
builder: (BuildContext context, Widget? child) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
restorationScopeId: 'app',
|
restorationScopeId: 'app',
|
||||||
|
|
@ -141,7 +139,7 @@ class _MyAppState extends State<MyApp> {
|
||||||
inputDecorationTheme:
|
inputDecorationTheme:
|
||||||
const InputDecorationTheme(border: OutlineInputBorder()),
|
const InputDecorationTheme(border: OutlineInputBorder()),
|
||||||
),
|
),
|
||||||
themeMode: widget.settingsController.themeMode,
|
themeMode: context.watch<SettingsChangeProvider>().themeMode,
|
||||||
home: Stack(
|
home: Stack(
|
||||||
children: [
|
children: [
|
||||||
FutureBuilder<bool>(
|
FutureBuilder<bool>(
|
||||||
|
|
@ -149,9 +147,7 @@ class _MyAppState extends State<MyApp> {
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.hasData) {
|
if (snapshot.hasData) {
|
||||||
return snapshot.data!
|
return snapshot.data!
|
||||||
? HomeView(
|
? HomeView()
|
||||||
settingsController: widget.settingsController,
|
|
||||||
)
|
|
||||||
: _showOnboarding
|
: _showOnboarding
|
||||||
? OnboardingView(
|
? OnboardingView(
|
||||||
callbackOnSuccess: () {
|
callbackOnSuccess: () {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,10 @@
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:twonly/src/services/settings_service.dart';
|
||||||
|
|
||||||
import 'settings_service.dart';
|
class SettingsChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
|
|
||||||
/// 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);
|
|
||||||
|
|
||||||
// Make SettingsService a private variable so it is not used directly.
|
// 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
|
// Make ThemeMode a private variable so it is not updated directly without
|
||||||
// also persisting the changes with the SettingsService.
|
// also persisting the changes with the SettingsService.
|
||||||
|
|
@ -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<ThemeMode>(
|
|
||||||
// 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'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:twonly/src/components/flame.dart';
|
import 'package:twonly/src/components/flame.dart';
|
||||||
import 'package:twonly/src/components/initialsavatar.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/chat_item_details_view.dart';
|
||||||
import 'package:twonly/src/views/home_view.dart';
|
import 'package:twonly/src/views/home_view.dart';
|
||||||
import 'package:twonly/src/views/media_viewer_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:twonly/src/views/search_username_view.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
@ -70,12 +72,23 @@ class _ChatListViewState extends State<ChatListView> {
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(AppLocalizations.of(context)!.chatsTitle),
|
title: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => ProfileView(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Text("twonly"),
|
||||||
|
),
|
||||||
|
// title:
|
||||||
actions: [
|
actions: [
|
||||||
NotificationBadge(
|
NotificationBadge(
|
||||||
count: context.watch<ContactChangeProvider>().newContactRequests,
|
count: context.watch<ContactChangeProvider>().newContactRequests,
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: Icon(Icons.person_add),
|
icon: FaIcon(FontAwesomeIcons.userPlus, size: 18),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
|
|
@ -85,6 +98,17 @@ class _ChatListViewState extends State<ChatListView> {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => ProfileView(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
icon: FaIcon(FontAwesomeIcons.gear, size: 19),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,12 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:pie_menu/pie_menu.dart';
|
import 'package:pie_menu/pie_menu.dart';
|
||||||
import 'camera_preview_view.dart';
|
import 'camera_preview_view.dart';
|
||||||
import 'chat_list_view.dart';
|
import 'chat_list_view.dart';
|
||||||
import 'profile_view.dart';
|
|
||||||
import '../settings/settings_controller.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
Function(int) globalUpdateOfHomeViewPageIndex = (a) {};
|
Function(int) globalUpdateOfHomeViewPageIndex = (a) {};
|
||||||
|
|
||||||
class HomeView extends StatefulWidget {
|
class HomeView extends StatefulWidget {
|
||||||
const HomeView({super.key, required this.settingsController});
|
const HomeView({super.key});
|
||||||
final SettingsController settingsController;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<HomeView> createState() => HomeViewState();
|
State<HomeView> createState() => HomeViewState();
|
||||||
|
|
@ -71,7 +68,7 @@ class HomeViewState extends State<HomeView> {
|
||||||
children: [
|
children: [
|
||||||
ChatListView(),
|
ChatListView(),
|
||||||
CameraPreviewViewPermission(),
|
CameraPreviewViewPermission(),
|
||||||
ProfileView(settingsController: widget.settingsController)
|
// ProfileView(settingsController: widget.settingsController)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
bottomNavigationBar: BottomNavigationBar(
|
bottomNavigationBar: BottomNavigationBar(
|
||||||
|
|
@ -86,8 +83,8 @@ class HomeViewState extends State<HomeView> {
|
||||||
icon: FaIcon(FontAwesomeIcons.camera),
|
icon: FaIcon(FontAwesomeIcons.camera),
|
||||||
label: "",
|
label: "",
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
// BottomNavigationBarItem(
|
||||||
icon: FaIcon(FontAwesomeIcons.userShield), label: ""),
|
// icon: FaIcon(FontAwesomeIcons.userShield), label: ""),
|
||||||
],
|
],
|
||||||
onTap: (int index) {
|
onTap: (int index) {
|
||||||
activePageIdx = index;
|
activePageIdx = index;
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:twonly/src/model/json/user_data.dart';
|
import 'package:twonly/src/model/json/user_data.dart';
|
||||||
import 'package:restart_app/restart_app.dart';
|
import 'package:restart_app/restart_app.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:twonly/src/settings/settings_controller.dart';
|
import 'package:twonly/src/providers/settings_change_provider.dart';
|
||||||
import 'package:twonly/src/settings/settings_view.dart';
|
|
||||||
import 'package:twonly/src/utils/storage.dart';
|
import 'package:twonly/src/utils/storage.dart';
|
||||||
|
|
||||||
class ProfileView extends StatefulWidget {
|
class ProfileView extends StatefulWidget {
|
||||||
const ProfileView({super.key, required this.settingsController});
|
const ProfileView({super.key});
|
||||||
|
|
||||||
final SettingsController settingsController;
|
// final SettingsController settingsController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ProfileView> createState() => _ProfileViewState();
|
State<ProfileView> createState() => _ProfileViewState();
|
||||||
|
|
@ -20,42 +20,68 @@ class _ProfileViewState extends State<ProfileView> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: FutureBuilder(
|
title: FutureBuilder(
|
||||||
future: _userData,
|
future: _userData,
|
||||||
builder: (context, snap) {
|
builder: (context, snap) {
|
||||||
if (snap.hasData) {
|
if (snap.hasData) {
|
||||||
return Text("Hello ${snap.data!.username}!");
|
return Text("Settings");
|
||||||
} else {
|
// return Text("Hello ${snap.data!.username}!");
|
||||||
return Container();
|
} else {
|
||||||
}
|
return Container();
|
||||||
}),
|
}
|
||||||
actions: [
|
},
|
||||||
IconButton(
|
),
|
||||||
icon: const Icon(Icons.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<ThemeMode>(
|
||||||
|
// Read the selected themeMode from the controller
|
||||||
|
value: context.watch<SettingsChangeProvider>().themeMode,
|
||||||
|
// Call the updateThemeMode method any time the user selects a theme.
|
||||||
|
onChanged: (theme) {
|
||||||
|
context.read<SettingsChangeProvider>().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: () {
|
onPressed: () {
|
||||||
// Navigate to the settings page. If the user leaves and returns
|
showLicensePage(context: context);
|
||||||
// to the app after it has been killed while running in the
|
},
|
||||||
// background, the navigation stack is restored.
|
child: Text('Show Licenses'),
|
||||||
Navigator.push(
|
),
|
||||||
context,
|
FilledButton.icon(
|
||||||
MaterialPageRoute(
|
onPressed: () async {
|
||||||
builder: (context) =>
|
await deleteLocalUserData();
|
||||||
SettingsView(controller: widget.settingsController)),
|
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)),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue