Skip to content
Snippets Groups Projects
Commit d90c2fa3 authored by Benoît Harrault's avatar Benoît Harrault
Browse files

Add settings page (username, security token)

parent ae63e6b1
No related branches found
No related tags found
1 merge request!37Resolve "Add settings page with security token"
Pipeline #4659 passed
This commit is part of merge request !37. Comments created here will be created in the context of that merge request.
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
app.versionName=0.0.34
app.versionCode=34
app.versionName=0.0.35
app.versionCode=35
......@@ -5,6 +5,7 @@
"bottom_nav_home": "Home",
"bottom_nav_discoveries": "Discoveries",
"bottom_nav_repartition": "Statistics",
"bottom_nav_settings": "Settings",
"global_statistics": "Global statistics",
"statistics_total_scrobbles_count": "Total scrobbles count: {count}",
......@@ -23,6 +24,11 @@
"top_artists_title": "Top artists ({daysCount} days)",
"settings_title": "Settings",
"settings_label_username": "Username: ",
"settings_label_security_token": "Security token: ",
"settings_button_save": "Save",
"MON": "MON",
"TUE": "TUE",
"WED": "WED",
......
......@@ -5,6 +5,7 @@
"bottom_nav_home": "Accueil",
"bottom_nav_discoveries": "Découvertes",
"bottom_nav_repartition": "Statistiques",
"bottom_nav_settings": "Paramètres",
"global_statistics": "Statistiques globales d'écoutes",
"statistics_total_scrobbles_count": "Nombre total d'écoutes : {count}",
......@@ -23,6 +24,11 @@
"top_artists_title": "Top artistes ({daysCount} jours)",
"settings_title": "Paramètres",
"settings_label_username": "Utilisateur : ",
"settings_label_security_token": "Jeton de sécurité : ",
"settings_button_save": "Enregistrer",
"MON": "LUN",
"TUE": "MAR",
"WED": "MER",
......
Add settings page (username, security token).
Ajout d'une page de paramètres (nom d'utilisateur, jeton de sécurité).
......@@ -3,7 +3,7 @@ import 'package:hydrated_bloc/hydrated_bloc.dart';
class BottomNavCubit extends HydratedCubit<int> {
BottomNavCubit() : super(0);
int pagesCount = 3;
int pagesCount = 4;
void updateIndex(int index) {
if (isIndexAllowed(index)) {
......
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
part 'settings_state.dart';
class SettingsCubit extends HydratedCubit<SettingsState> {
SettingsCubit() : super(const SettingsState());
String getUsername() {
return state.username ?? '';
}
String getSecurityToken() {
return state.securityToken ?? '';
}
void setValues({
String? username,
String? securityToken,
}) {
emit(SettingsState(
username: username != null ? username : state.username,
securityToken: securityToken != null ? securityToken : state.securityToken,
));
}
@override
SettingsState? fromJson(Map<String, dynamic> json) {
String username = json['username'] as String;
String securityToken = json['securityToken'] as String;
return SettingsState(
username: username,
securityToken: securityToken,
);
}
@override
Map<String, String>? toJson(SettingsState state) {
return <String, String>{
'username': state.username ?? '',
'securityToken': state.securityToken ?? '',
};
}
}
part of 'settings_cubit.dart';
@immutable
class SettingsState extends Equatable {
const SettingsState({
this.username,
this.securityToken,
});
final String? username;
final String? securityToken;
@override
List<String?> get props => <String?>[
username,
securityToken,
];
Map<String, String?> get values => <String, String?>{
'username': username,
'securityToken': securityToken,
};
}
......@@ -16,6 +16,7 @@ import 'package:scrobbles/cubit/data_statistics_global_cubit.dart';
import 'package:scrobbles/cubit/data_statistics_recent_cubit.dart';
import 'package:scrobbles/cubit/data_timeline_cubit.dart';
import 'package:scrobbles/cubit/data_top_artists_cubit.dart';
import 'package:scrobbles/cubit/settings_cubit.dart';
import 'package:scrobbles/ui/skeleton.dart';
void main() async {
......@@ -49,6 +50,7 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<SettingsCubit>(create: (context) => SettingsCubit()),
BlocProvider<BottomNavCubit>(create: (context) => BottomNavCubit()),
BlocProvider<DataCountsByDayCubit>(create: (context) => DataCountsByDayCubit()),
BlocProvider<DataCountsByHourCubit>(create: (context) => DataCountsByHourCubit()),
......
import 'package:flutter/material.dart';
import 'package:scrobbles/ui/widgets/header_app.dart';
import 'package:scrobbles/ui/widgets/settings_form.dart';
class ScreenSettings extends StatelessWidget {
const ScreenSettings({super.key});
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
SizedBox(height: 8),
AppHeader(text: 'settings_title'),
SizedBox(height: 8),
SettingsForm(),
],
);
}
}
......@@ -5,6 +5,7 @@ import 'package:flutter_swipe/flutter_swipe.dart';
import 'package:scrobbles/cubit/bottom_nav_cubit.dart';
import 'package:scrobbles/ui/screens/discoveries.dart';
import 'package:scrobbles/ui/screens/home.dart';
import 'package:scrobbles/ui/screens/settings.dart';
import 'package:scrobbles/ui/screens/statistics.dart';
import 'package:scrobbles/ui/widgets/app_bar.dart';
import 'package:scrobbles/ui/widgets/bottom_nav_bar.dart';
......@@ -23,6 +24,7 @@ class _SkeletonScreenState extends State<SkeletonScreen> {
const ScreenHome(),
const ScreenDiscoveries(),
const ScreenStatistics(),
const ScreenSettings(),
];
return Scaffold(
......
......@@ -54,6 +54,10 @@ class BottomNavBar extends StatelessWidget {
icon: const Icon(Ionicons.bar_chart_outline),
label: tr('bottom_nav_repartition'),
),
BottomNavigationBarItem(
icon: const Icon(Ionicons.settings_outline),
label: tr('bottom_nav_settings'),
),
],
);
},
......
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:unicons/unicons.dart';
import 'package:scrobbles/cubit/settings_cubit.dart';
class SettingsForm extends StatefulWidget {
const SettingsForm({super.key});
@override
State<SettingsForm> createState() => _SettingsFormState();
}
class _SettingsFormState extends State<SettingsForm> {
final usernameController = TextEditingController();
final securityTokenController = TextEditingController();
@override
void dispose() {
usernameController.dispose();
securityTokenController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
SettingsCubit settings = BlocProvider.of<SettingsCubit>(context);
usernameController.text = settings.getUsername();
securityTokenController.text = settings.getSecurityToken();
void saveSettings() {
BlocProvider.of<SettingsCubit>(context).setValues(
username: usernameController.text,
securityToken: securityTokenController.text,
);
}
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Text('settings_label_username').tr(),
TextFormField(
controller: usernameController,
decoration: InputDecoration(
border: UnderlineInputBorder(),
),
),
SizedBox(height: 16),
Text('settings_label_security_token').tr(),
TextFormField(
controller: securityTokenController,
decoration: InputDecoration(
border: UnderlineInputBorder(),
),
),
SizedBox(height: 20),
ElevatedButton(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(UniconsLine.save),
SizedBox(width: 8),
Text('settings_button_save').tr(),
],
),
onPressed: () => saveSettings(),
),
],
);
}
}
......@@ -3,7 +3,7 @@ description: Display scrobbles data and charts
publish_to: 'none'
version: 0.0.34+34
version: 0.0.35+35
environment:
sdk: '^3.0.0'
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment