Add local storage + update audioIds for Article + fix small layout bugs

This commit is contained in:
Fransolet Thomas 2022-12-22 14:32:43 +01:00
parent d185c2c1e4
commit 99aaad3f50
17 changed files with 312 additions and 138 deletions

View File

@ -23,7 +23,7 @@ class AudioInputContainer extends StatefulWidget {
this.onChanged,
this.imageFit = BoxFit.cover,
this.isSmall = false,
this.fontSize = 25
this.fontSize = 20
}) : super(key: key);
@override
@ -138,8 +138,9 @@ class _AudioInputContainerState extends State<AudioInputContainer> {
}
Future<ResourceDTO> getResource(String resourceIdToShow, dynamic appContext) async {
ResourceDTO resource = await appContext.getContext().clientAPI.resourceApi.resourceGetDetail(resourceIdToShow);
return resource;
// Just in resource tab detail not here
//ResourceDTO resource = await appContext.getContext().clientAPI.resourceApi.resourceGetDetail(resourceIdToShow);
return new ResourceDTO();
}
boxDecoration(ResourceDTO resourceDTO, appContext) {

View File

@ -3,6 +3,7 @@ import 'dart:typed_data';
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:manager_app/Models/managerContext.dart';
import 'package:manager_app/app_context.dart';
import 'package:manager_app/constants.dart';
import 'package:managerapi/api.dart';
@ -178,7 +179,8 @@ class _AudioPlayerContainerState extends State<AudioPlayerContainer> {
Future<Uint8List> getAudio(String resourceId, AppContext appContext) async {
try {
var url = "https://api.mymuseum.be/api/Resource/"+resourceId; // TO TEST TODO UPDATE ROUTE
ManagerAppContext managerAppContext = appContext.getContext() as ManagerAppContext;
var url = managerAppContext.host + "/api/Resource/" + resourceId; // TO TEST TODO UPDATE ROUTE
print("DOWNLOAD AUDDDDIOOOOO ------------");
print(url);
//HttpClient client2 = HttpClient();

View File

@ -1,15 +1,21 @@
import 'dart:ui';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:manager_app/Components/rounded_button.dart';
import 'package:manager_app/Components/text_form_input_container.dart';
import 'package:manager_app/Models/managerContext.dart';
import 'package:manager_app/Screens/Resources/select_resource_modal.dart';
import 'package:manager_app/app_context.dart';
import 'package:manager_app/constants.dart';
import 'package:managerapi/api.dart';
import 'package:collection/collection.dart';
import 'package:provider/provider.dart';
showMultiStringInput (String label, String modalLabel, bool isTitle, List<TranslationDTO> values, List<TranslationDTO> newValues, Function onGetResult, int maxLines, BuildContext context) { /*Function onSelect,*/
import 'audio_input_container.dart';
showMultiStringInput (String label, String modalLabel, bool isTitle, List<TranslationDTO> values, List<TranslationDTO> newValues, Function onGetResult, int maxLines, bool isAudio, BuildContext context) { /*Function onSelect,*/
showDialog(
builder: (BuildContext context) => AlertDialog(
shape: RoundedRectangleBorder(
@ -23,7 +29,7 @@ showMultiStringInput (String label, String modalLabel, bool isTitle, List<Transl
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: getTranslations(context, Provider.of<AppContext>(context), label, isTitle, newValues),
children: getTranslations(context, Provider.of<AppContext>(context), label, isTitle, isAudio, newValues),
),
),
),
@ -84,7 +90,7 @@ showMultiStringInput (String label, String modalLabel, bool isTitle, List<Transl
);
}
getTranslations(BuildContext context, AppContext appContext, String label, bool isTitle, List<TranslationDTO> newValues) {
getTranslations(BuildContext context, AppContext appContext, String label, bool isTitle, bool isAudio, List<TranslationDTO> newValues) {
List<Widget> translations = <Widget>[];
ManagerAppContext managerAppContext = appContext.getContext();
for(var language in managerAppContext.selectedConfiguration.languages) {
@ -111,6 +117,7 @@ getTranslations(BuildContext context, AppContext appContext, String label, bool
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
!isAudio ?
TextFormInputContainer(
label: label,
color: kWhite,
@ -119,6 +126,18 @@ getTranslations(BuildContext context, AppContext appContext, String label, bool
onChanged: (value) {
newValues.where((element) => element.language == language).first.value = value;
},
) :
Container(
width: 250,
height: 120,
child: AudioInputContainer(
label: "Audio :",
initialValue: newValues.where((element) => element.language == language).first.value,
color: kPrimaryColor,
onChanged: (ResourceDTO resource) {
newValues.where((element) => element.language == language).first.value = resource.id;
},
),
),
],
),
@ -147,5 +166,3 @@ showValues(List<TranslationDTO> newValues) {
});
return valuesToShow;
}*/

View File

@ -14,6 +14,7 @@ class MultiStringContainer extends StatelessWidget {
final Function onGetResult;
final int maxLines;
final bool isTitle;
final bool isAudio;
final double fontSize;
const MultiStringContainer({
Key key,
@ -24,6 +25,7 @@ class MultiStringContainer extends StatelessWidget {
this.onGetResult,
this.maxLines,
this.isTitle,
this.isAudio = false,
this.fontSize = 25,
}) : super(key: key);
@ -56,7 +58,8 @@ class MultiStringContainer extends StatelessWidget {
initialValue.forEach((value) {
newValues.add(TranslationDTO.fromJson(jsonDecode(jsonEncode(value))));
});
showMultiStringInput(label, modalLabel, isTitle, initialValue, newValues, onGetResult, maxLines, context);
showMultiStringInput(label, modalLabel, isTitle, initialValue, newValues, onGetResult, maxLines, isAudio, context);
}
},
child: Container(
@ -68,7 +71,7 @@ class MultiStringContainer extends StatelessWidget {
padding: const EdgeInsets.only(left: 5, right: 5, top: 15, bottom: 15),
child: Center(
child: AutoSizeText(
"Changer les traductions",
isAudio ? "Changer audios" : "Changer traductions",
style: TextStyle(color: kWhite),
maxLines: 2,
)

View File

@ -11,6 +11,7 @@ class RoundedInputField extends StatelessWidget {
final int maxLength;
final bool isEmail;
final double fontSize;
final String autofill;
const RoundedInputField({
Key key,
this.hintText,
@ -23,6 +24,7 @@ class RoundedInputField extends StatelessWidget {
this.maxLength, // 50
this.isEmail = false,
this.fontSize = 20,
this.autofill,
}) : super(key: key);
@override
@ -34,6 +36,7 @@ class RoundedInputField extends StatelessWidget {
initialValue: initialValue,
cursorColor: textColor,
maxLength: maxLength,
autofillHints: [autofill],
keyboardType: isEmail ? TextInputType.emailAddress : TextInputType.text,
style: TextStyle(fontSize: fontSize, color: textColor),
decoration: InputDecoration(

View File

@ -8,7 +8,7 @@ class RoundedPasswordField extends StatefulWidget {
const RoundedPasswordField({
Key key,
this.onChanged,
this.initialValue,
this.initialValue
}) : super(key: key);
@override
@ -25,6 +25,7 @@ class _RoundedPasswordFieldState extends State<RoundedPasswordField> {
obscureText: isVisible,
onChanged: widget.onChanged,
initialValue: widget.initialValue,
autofillHints: [AutofillHints.password],
cursorColor: kPrimaryColor,
style: TextStyle(fontSize: 20, color: kBlack),
decoration: InputDecoration(

View File

@ -66,7 +66,22 @@ class _UploadOnlineResourceContainerState extends State<UploadOnlineResourceCont
return Image.network(
urlResourceToShow,
height: 200,
fit:BoxFit.scaleDown
fit:BoxFit.scaleDown,
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null) {
return child;
}
return Center(
child: CircularProgressIndicator(
color: kPrimaryColor,
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes
: null,
),
);
},
);
}
}

View File

@ -6,6 +6,7 @@ import 'package:managerapi/api.dart';
class ManagerAppContext with ChangeNotifier{
String email;
String instanceId;
String host;
TokenDTO token;
Client clientAPI;
String currentRoute;
@ -18,6 +19,6 @@ class ManagerAppContext with ChangeNotifier{
// Implement toString to make it easier to see information about
@override
String toString() {
return 'ManagerAppContext{email: $email, token: $token, currentRoute: $currentRoute}, selectedConfiguration: $selectedConfiguration, selectedSection: $selectedSection}';
return 'ManagerAppContext{email: $email, host: $host, token: $token, currentRoute: $currentRoute}, selectedConfiguration: $selectedConfiguration, selectedSection: $selectedSection}';
}
}

View File

@ -72,58 +72,76 @@ class _ArticleConfigState extends State<ArticleConfig> {
child: Column(
children: [
Container(
height: size.height * 0.1,
height: size.height * 0.15,
//width: size.width * 0.5,//,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
MultiStringContainer(
label: "Contenu affiché :",
modalLabel: "Contenu",
color: kPrimaryColor,
initialValue: articleDTO != null ? articleDTO.content : [],
isTitle: false,
onGetResult: (value) {
setState(() {
if (articleDTO.content != value) {
articleDTO.content = value;
//save(true, articleDTO, appContext);
widget.onChanged(jsonEncode(articleDTO).toString());
}
});
},
maxLines: 1,
Column(
children: [
MultiStringContainer(
label: "Contenu affiché :",
modalLabel: "Contenu",
color: kPrimaryColor,
initialValue: articleDTO != null ? articleDTO.content : [],
isTitle: false,
onGetResult: (value) {
setState(() {
if (articleDTO.content != value) {
articleDTO.content = value;
//save(true, articleDTO, appContext);
widget.onChanged(jsonEncode(articleDTO).toString());
}
});
},
maxLines: 1,
),
CheckInputContainer(
label: "Contenu au-dessus :",
isChecked: articleDTO.isContentTop,
onChanged: (value) {
setState(() {
//print(value);
articleDTO.isContentTop = value;
widget.onChanged(jsonEncode(articleDTO).toString());
});
},
),
],
),
CheckInputContainer(
label: "Contenu au-dessus :",
isChecked: articleDTO.isContentTop,
onChanged: (value) {
setState(() {
//print(value);
articleDTO.isContentTop = value;
widget.onChanged(jsonEncode(articleDTO).toString());
});
},
),
AudioInputContainer(
label: "Audio :",
initialValue: articleDTO.audioId,
color: kPrimaryColor,
onChanged: (ResourceDTO resource) {
articleDTO.audioId = resource.id;
widget.onChanged(jsonEncode(articleDTO).toString());
},
),
CheckInputContainer(
label: "Lecture auto audio :",
isChecked: articleDTO.isReadAudioAuto,
onChanged: (value) {
setState(() {
//print(value);
articleDTO.isReadAudioAuto = value;
widget.onChanged(jsonEncode(articleDTO).toString());
});
},
Column(
children: [
MultiStringContainer(
label: "Audio :",
isAudio: true,
modalLabel: "Audio",
color: kPrimaryColor,
initialValue: articleDTO != null ? articleDTO.audioIds : [],
isTitle: false,
onGetResult: (value) {
setState(() {
if (articleDTO.audioIds != value) {
articleDTO.audioIds = value;
//save(true, articleDTO, appContext);
widget.onChanged(jsonEncode(articleDTO).toString());
}
});
},
maxLines: 1,
),
CheckInputContainer(
label: "Lecture auto audio :",
isChecked: articleDTO.isReadAudioAuto,
onChanged: (value) {
setState(() {
//print(value);
articleDTO.isReadAudioAuto = value;
widget.onChanged(jsonEncode(articleDTO).toString());
});
},
),
],
),
],
),
@ -141,7 +159,7 @@ class _ArticleConfigState extends State<ArticleConfig> {
padding: const EdgeInsets.only(top: 40, left: 10, right: 10, bottom: 10),
child: Container(
height: 250,
width: size.height * 0.95,
width: size.width * 0.95,
child: ReorderableListView(
onReorder: _onReorder,
scrollDirection: Axis.horizontal,
@ -162,7 +180,7 @@ class _ArticleConfigState extends State<ArticleConfig> {
testToSend = testToSend.where((element) => element.source_ != null).toList();
var articleToSend = new ArticleDTO();
articleToSend.images = testToSend;
articleToSend.audioId = articleDTO.audioId;
articleToSend.audioIds = articleDTO.audioIds;
articleToSend.isContentTop = articleDTO.isContentTop;
articleToSend.content = articleDTO.content;
articleToSend.isReadAudioAuto = articleDTO.isReadAudioAuto;

View File

@ -83,7 +83,22 @@ class _ListViewCardGeoPointImagesState extends State<ListViewCardGeoPointImages>
Center(
child: Image.network(
imageGeoPoint.imageSource,
fit:BoxFit.scaleDown
fit:BoxFit.scaleDown,
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null) {
return child;
}
return Center(
child: CircularProgressIndicator(
color: kPrimaryColor,
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes
: null,
),
);
},
),
)
/*Align(

View File

@ -1,3 +1,5 @@
import 'dart:html';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:manager_app/Models/managerContext.dart';
@ -134,6 +136,8 @@ class _BodyState extends State<Body> {
setState(() {
print("Logout");
Storage localStorage = window.localStorage;
localStorage.clear();
ManagerAppContext managerAppContext = appContext.getContext();
managerAppContext.token = null;
appContext.setContext(managerAppContext);

View File

@ -1,5 +1,6 @@
import 'package:manager_app/Components/audio_player.dart';
import 'package:manager_app/app_context.dart';
import 'package:manager_app/constants.dart';
import 'package:managerapi/api.dart';
import 'package:flutter/material.dart';
@ -8,13 +9,43 @@ getElementForResource(dynamic resourceDTO, AppContext appContext) {
case ResourceType.image:
return Image.network(
appContext.getContext().clientAPI.resourceApi.apiClient.basePath+"/api/Resource/"+ resourceDTO.id,
fit:BoxFit.fill
fit:BoxFit.fill,
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null) {
return child;
}
return Center(
child: CircularProgressIndicator(
color: kPrimaryColor,
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes
: null,
),
);
},
);
break;
case ResourceType.imageUrl:
return Image.network(
resourceDTO.data,
fit:BoxFit.fill
fit:BoxFit.fill,
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent loadingProgress) {
if (loadingProgress == null) {
return child;
}
return Center(
child: CircularProgressIndicator(
color: kPrimaryColor,
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
loadingProgress.expectedTotalBytes
: null,
),
);
},
);
break;
case ResourceType.audio:

View File

@ -1,6 +1,7 @@
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:manager_app/Components/message_notification.dart';
import 'package:manager_app/Components/resource_tab.dart';
import 'package:flutter/material.dart';
@ -89,10 +90,18 @@ dynamic showNewResource(AppContext appContext, BuildContext context) async {
textColor: kWhite,
press: () {
if (resourceDetailDTO.label != null && resourceDetailDTO.label.trim() != '') {
if (resourceDetailDTO.data != null || filesToSendWeb.length > 0 || filesToSend.length > 0) {
Navigator.pop(context, [resourceDetailDTO, filesToSend, filesToSendWeb]);
if(kIsWeb) {
if(resourceDetailDTO.data != null || filesToSendWeb != null) {
Navigator.pop(context, [resourceDetailDTO, filesToSend, filesToSendWeb]);
} else {
showNotification(Colors.orange, kWhite, 'Aucun fichier n\'a été chargé', context, null);
}
} else {
showNotification(Colors.orange, kWhite, 'Aucun fichier n\'a été chargé', context, null);
if (resourceDetailDTO.data != null || filesToSendWeb.length > 0 || filesToSend.length > 0) {
Navigator.pop(context, [resourceDetailDTO, filesToSend, filesToSendWeb]);
} else {
showNotification(Colors.orange, kWhite, 'Aucun fichier n\'a été chargé', context, null);
}
}
} else {
showNotification(Colors.orange, kWhite, 'Veuillez donner un nom à la ressource', context, null);

View File

@ -2,6 +2,7 @@ import 'dart:html';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:manager_app/Components/loading_common.dart';
import 'package:manager_app/Components/message_notification.dart';
import 'package:manager_app/Components/rounded_button.dart';
@ -34,6 +35,8 @@ class _LoginScreenState extends State<LoginScreen> {
bool isLoading = false;
bool isRememberMe = false;
String pageTitle = "MyMuseum";
String token;
Storage localStorage = window.localStorage;
void authenticateTRY(dynamic appContext) async {
//print("try auth.. ");
@ -44,7 +47,7 @@ class _LoginScreenState extends State<LoginScreen> {
clientAPI = Client(this.host);
if (this.email != null && this.password != null && this.host != null) {
if (this.email != null && this.password != null || this.token != null) {
// if () {} // Add if token exist and not null + not expired
try {
@ -58,11 +61,25 @@ class _LoginScreenState extends State<LoginScreen> {
TokenDTO token = await clientAPI.authenticationApi.authenticationAuthenticateWithJson(loginDTO);
setAccessToken(token.accessToken);
if (isRememberMe) {
if(!isRememberMe) {
localStorage.clear();
} else {
if(!localStorage.containsKey("remember")) {
localStorage.addEntries({"remember": "true"}.entries);
}
if(!localStorage.containsKey("email") && !localStorage.containsKey("token")) {
localStorage.addEntries({"email": email}.entries);
localStorage.addEntries({"token": token.accessToken}.entries);
}
}
// Desktop
/*if (isRememberMe) {
Session updatedSession = new Session(rememberMe: isRememberMe, host: host, email: email, password: password);
// update JSON FILE
FileHelper().writeSession(updatedSession);
}
}*/
showNotification(kSuccess, kWhite, 'Connexion réussie', context, null);
@ -74,6 +91,7 @@ class _LoginScreenState extends State<LoginScreen> {
// store user info locally
managerAppContext.email = email;
managerAppContext.host = host;
managerAppContext.instanceId = token.instanceId;
managerAppContext.token = token;
managerAppContext.clientAPI = clientAPI;
@ -85,6 +103,14 @@ class _LoginScreenState extends State<LoginScreen> {
isLoading = false;
});
//Navigator.pushNamed(context, '/main');
/*Navigator.pushNamedAndRemoveUntil(
context,
'/main',
(Route<dynamic> route) => false // For pushAndRemoveUntil
);*/
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
@ -117,10 +143,20 @@ class _LoginScreenState extends State<LoginScreen> {
@override
void initState() {
this.isRememberMe = widget.session.rememberMe;
this.host = "https://api.mymuseum.be"; // "http://localhost:5000" //widget.session.host; // MDLF "http://192.168.1.19:8089" // "https://api.mymuseum.be"
//this.isRememberMe = widget.session.rememberMe;
this.host = "http://localhost:5000"; // "http://localhost:5000" //widget.session.host; // MDLF "http://192.168.1.19:8089" // "https://api.mymuseum.be"
//this.email = "test@email.be"; //widget.session.email;
//this.password = "kljqsdkljqsd"; //widget.session.password;
if(localStorage.containsKey("remember")) {
this.isRememberMe = true;
if(localStorage.containsKey("email")) {
this.email = localStorage.entries.where((element) => element.key == "email").first.value;
}
if(localStorage.containsKey("token")) {
this.token = localStorage.entries.where((element) => element.key == "token").first.value;
}
}
super.initState();
}
@ -157,6 +193,11 @@ class _LoginScreenState extends State<LoginScreen> {
initInstance(appContext.getContext());
if(mounted && appContext != null && this.token != null)
{
this.authenticateTRY(appContext);
}
return Scaffold(
body: Center(
child: SingleChildScrollView(
@ -208,62 +249,73 @@ class _LoginScreenState extends State<LoginScreen> {
initialValue: host,
icon: Icons.home
),*/
SizedBox(
width: size.width*0.2,
child: RoundedInputField(
hintText: "E-mail",
onChanged: (value) {
email = value;
},
icon: Icons.person,
initialValue: email,
isEmail: true,
),
),
SizedBox(
width: size.width *0.2,
child: RoundedPasswordField(
initialValue: password,
onChanged: (value) {
password = value;
},
),
),
if(!kIsWeb) Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: Checkbox(
checkColor: kTextLightColor,
activeColor: kPrimaryColor,
value: this.isRememberMe,
onChanged: (bool value) {
setState(() {
this.isRememberMe = value;
});
},
Form(
key: widget.key,
child: AutofillGroup(
child: Column(
children: [
SizedBox(
width: size.width*0.2,
child: RoundedInputField(
hintText: "E-mail",
autofill: AutofillHints.email,
onChanged: (value) {
email = value;
},
icon: Icons.person,
initialValue: email,
isEmail: true,
),
),
),
Text("Se souvenir de moi", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500),),
],
SizedBox(
width: size.width*0.2,
child: RoundedPasswordField(
initialValue: password,
onChanged: (value) {
password = value;
},
),
),
if(kIsWeb) Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: Checkbox(
checkColor: kTextLightColor,
activeColor: kPrimaryColor,
value: this.isRememberMe,
onChanged: (bool value) {
setState(() {
this.isRememberMe = value;
});
},
),
),
Text("Se souvenir de moi", style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500),),
],
),
),
SizedBox(height: size.height * 0.05),
!isLoading ? RoundedButton(
text: "SE CONNECTER",
fontSize: 25,
vertical: 25,
horizontal: 45,
press: () {
TextInput.finishAutofillContext();
authenticateTRY(appContext);
},
): Container(
height: size.height * 0.1,
child: LoadingCommon()
),
],
)
),
),
SizedBox(height: size.height * 0.05),
!isLoading ? RoundedButton(
text: "SE CONNECTER",
fontSize: 25,
vertical: 25,
horizontal: 45,
press: () {
authenticateTRY(appContext);
},
): Container(
height: size.height * 0.1,
child: LoadingCommon()
),
],
),
),

View File

@ -11,7 +11,7 @@ Name | Type | Description | Notes
**content** | [**List<TranslationDTO>**](TranslationDTO.md) | | [optional] [default to const []]
**qrCode** | **String** | | [optional]
**isContentTop** | **bool** | | [optional]
**audioId** | **String** | | [optional]
**audioIds** | [**List<TranslationDTO>**](TranslationDTO.md) | | [optional] [default to const []]
**isReadAudioAuto** | **bool** | | [optional]
**images** | [**List<ImageDTO>**](ImageDTO.md) | | [optional] [default to const []]

View File

@ -15,7 +15,7 @@ class ArticleDTO {
this.content,
this.qrCode,
this.isContentTop,
this.audioId,
this.audioIds,
this.isReadAudioAuto,
this.images,
});
@ -26,7 +26,7 @@ class ArticleDTO {
bool isContentTop;
String audioId;
List<TranslationDTO> audioIds;
bool isReadAudioAuto;
@ -37,7 +37,7 @@ class ArticleDTO {
other.content == content &&
other.qrCode == qrCode &&
other.isContentTop == isContentTop &&
other.audioId == audioId &&
other.audioIds == audioIds &&
other.isReadAudioAuto == isReadAudioAuto &&
other.images == images;
@ -46,12 +46,12 @@ class ArticleDTO {
(content == null ? 0 : content.hashCode) +
(qrCode == null ? 0 : qrCode.hashCode) +
(isContentTop == null ? 0 : isContentTop.hashCode) +
(audioId == null ? 0 : audioId.hashCode) +
(audioIds == null ? 0 : audioIds.hashCode) +
(isReadAudioAuto == null ? 0 : isReadAudioAuto.hashCode) +
(images == null ? 0 : images.hashCode);
@override
String toString() => 'ArticleDTO[content=$content, qrCode=$qrCode, isContentTop=$isContentTop, audioId=$audioId, isReadAudioAuto=$isReadAudioAuto, images=$images]';
String toString() => 'ArticleDTO[content=$content, qrCode=$qrCode, isContentTop=$isContentTop, audioIds=$audioIds, isReadAudioAuto=$isReadAudioAuto, images=$images]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
@ -64,8 +64,8 @@ class ArticleDTO {
if (isContentTop != null) {
json[r'isContentTop'] = isContentTop;
}
if (audioId != null) {
json[r'audioId'] = audioId;
if (audioIds != null) {
json[r'audioIds'] = audioIds;
}
if (isReadAudioAuto != null) {
json[r'isReadAudioAuto'] = isReadAudioAuto;
@ -84,7 +84,7 @@ class ArticleDTO {
content: TranslationDTO.listFromJson(json[r'content']),
qrCode: json[r'qrCode'],
isContentTop: json[r'isContentTop'],
audioId: json[r'audioId'],
audioIds: TranslationDTO.listFromJson(json[r'audioIds']),
isReadAudioAuto: json[r'isReadAudioAuto'],
images: ImageDTO.listFromJson(json[r'images']),
);

View File

@ -2107,9 +2107,11 @@ components:
nullable: true
isContentTop:
type: boolean
audioId:
type: string
audioIds:
type: array
nullable: true
items:
$ref: '#/components/schemas/TranslationDTO'
isReadAudioAuto:
type: boolean
images: