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

Merge branch '2-add-settings-page-with-security-token' into 'master'

Resolve "Add settings page with security token"

Closes #2

See merge request !37
parents ae63e6b1 d90c2fa3
No related branches found
No related tags found
1 merge request!37Resolve "Add settings page with security token"
Pipeline #4662 passed
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