Merge branch 'main' into resolve-issue-missing-drag-scrolling

This commit is contained in:
Ragul Raj
2024-03-22 04:49:06 +05:30
committed by GitHub
14 changed files with 324 additions and 119 deletions

View File

@ -154,4 +154,16 @@ ClientException with SocketException: Connection failed (OS Error: Operation not
You can read more [here](https://docs.flutter.dev/platform-integration/macos/building#setting-up-entitlements) You can read more [here](https://docs.flutter.dev/platform-integration/macos/building#setting-up-entitlements)
### Android (Work in Progress)
Add the `multiDexEnabled true` line to the `defaultConfig` section at `android/app/build.gradle file`
```
android {
...
defaultConfig {
...
multiDexEnabled true
}
}
```

1
assets/completed.json Normal file
View File

@ -0,0 +1 @@
{"v":"5.1.16","fr":29.9700012207031,"ip":0,"op":30.0000012219251,"w":500,"h":500,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-158,21],[-63,116],[162,-109]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.129411764706,0.8,0.223529411765,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"ix":5},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"n":["0p833_0p833_0p167_0p167"],"t":0,"s":[0],"e":[100]},{"t":20.0000008146167}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-149.000006068894,"op":40.0000016292334,"st":-149.000006068894,"bm":0}],"markers":[]}

1
assets/saving.json Normal file

File diff suppressed because one or more lines are too long

View File

@ -9,6 +9,11 @@ const kGitUrl = "https://github.com/foss42/apidash";
const kIssueUrl = "$kGitUrl/issues"; const kIssueUrl = "$kGitUrl/issues";
const kDefaultUri = "api.apidash.dev"; const kDefaultUri = "api.apidash.dev";
const kAssetIntroMd = "assets/intro.md";
const kAssetSendingLottie = "assets/sending.json";
const kAssetSavingLottie = "assets/saving.json";
const kAssetSavedLottie = "assets/completed.json";
final kIsMacOS = !kIsWeb && Platform.isMacOS; final kIsMacOS = !kIsWeb && Platform.isMacOS;
final kIsWindows = !kIsWeb && Platform.isWindows; final kIsWindows = !kIsWeb && Platform.isWindows;
final kIsLinux = !kIsWeb && Platform.isLinux; final kIsLinux = !kIsWeb && Platform.isLinux;
@ -24,6 +29,7 @@ final kColorTransparentState =
MaterialStateProperty.all<Color>(Colors.transparent); MaterialStateProperty.all<Color>(Colors.transparent);
const kColorTransparent = Colors.transparent; const kColorTransparent = Colors.transparent;
const kColorWhite = Colors.white; const kColorWhite = Colors.white;
const kColorBlack = Colors.black;
const kColorRed = Colors.red; const kColorRed = Colors.red;
final kColorLightDanger = Colors.red.withOpacity(0.9); final kColorLightDanger = Colors.red.withOpacity(0.9);
const kColorDarkDanger = Color(0xffcf6679); const kColorDarkDanger = Color(0xffcf6679);
@ -46,6 +52,7 @@ final kCodeStyle = TextStyle(
const kHintOpacity = 0.6; const kHintOpacity = 0.6;
const kForegroundOpacity = 0.05; const kForegroundOpacity = 0.05;
const kOverlayBackgroundOpacity = 0.5;
const kTextStyleButton = TextStyle(fontWeight: FontWeight.bold); const kTextStyleButton = TextStyle(fontWeight: FontWeight.bold);
const kTextStyleButtonSmall = TextStyle(fontSize: 12); const kTextStyleButtonSmall = TextStyle(fontSize: 12);
@ -80,6 +87,7 @@ const kPh20t40 = EdgeInsets.only(
top: 40, top: 40,
); );
const kPh60 = EdgeInsets.symmetric(horizontal: 60); const kPh60 = EdgeInsets.symmetric(horizontal: 60);
const kPh60v60 = EdgeInsets.symmetric(vertical: 60, horizontal: 60);
const kP24CollectionPane = EdgeInsets.only( const kP24CollectionPane = EdgeInsets.only(
top: 24, top: 24,
left: 4.0, left: 4.0,
@ -515,3 +523,5 @@ const kLabelBusy = "Busy";
const kLabelCopy = "Copy"; const kLabelCopy = "Copy";
const kLabelSave = "Save"; const kLabelSave = "Save";
const kLabelDownload = "Download"; const kLabelDownload = "Download";
const kLabelSaving = "Saving";
const kLabelSaved = "Saved";

View File

@ -12,7 +12,7 @@ class CollectionPane extends ConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
var sm = ScaffoldMessenger.of(context); final overlayWidget = OverlayWidgetTemplate(context: context);
final collection = ref.watch(collectionStateNotifierProvider); final collection = ref.watch(collectionStateNotifierProvider);
final savingData = ref.watch(saveDataStateProvider); final savingData = ref.watch(saveDataStateProvider);
if (collection == null) { if (collection == null) {
@ -34,12 +34,18 @@ class CollectionPane extends ConsumerWidget {
onPressed: savingData onPressed: savingData
? null ? null
: () async { : () async {
overlayWidget.show(
widget:
const SavingOverlay(saveCompleted: false));
await ref await ref
.read(collectionStateNotifierProvider.notifier) .read(collectionStateNotifierProvider.notifier)
.saveData(); .saveData();
overlayWidget.hide();
sm.hideCurrentSnackBar(); overlayWidget.show(
sm.showSnackBar(getSnackBar("Saved")); widget: const SavingOverlay(saveCompleted: true));
await Future.delayed(const Duration(seconds: 1));
overlayWidget.hide();
}, },
icon: const Icon( icon: const Icon(
Icons.save, Icons.save,

View File

@ -17,19 +17,36 @@ class FormDataWidget extends ConsumerStatefulWidget {
class _FormDataBodyState extends ConsumerState<FormDataWidget> { class _FormDataBodyState extends ConsumerState<FormDataWidget> {
late int seed; late int seed;
final random = Random.secure(); final random = Random.secure();
late List<FormDataModel> rows; late List<FormDataModel> formRows;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
seed = random.nextInt(kRandMax); seed = random.nextInt(kRandMax);
} }
void _onFieldChange(String selectedId) {
ref.read(collectionStateNotifierProvider.notifier).update(
selectedId,
requestFormDataList: formRows.sublist(0, formRows.length - 1),
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final selectedId = ref.watch(selectedIdStateProvider); final selectedId = ref.watch(selectedIdStateProvider);
var formRows = ref.read(selectedRequestModelProvider)?.requestFormDataList; ref.watch(selectedRequestModelProvider
rows = .select((value) => value?.requestFormDataList?.length));
formRows == null || formRows.isEmpty ? [kFormDataEmptyModel] : formRows; var rF = ref.read(selectedRequestModelProvider)?.requestFormDataList;
bool isFormDataEmpty = rF == null || rF.isEmpty;
formRows = isFormDataEmpty
? [
kFormDataEmptyModel,
]
: rF +
[
kFormDataEmptyModel,
];
List<DataColumn> columns = const [ List<DataColumn> columns = const [
DataColumn2( DataColumn2(
@ -55,18 +72,20 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
]; ];
List<DataRow> dataRows = List<DataRow>.generate( List<DataRow> dataRows = List<DataRow>.generate(
rows.length, formRows.length,
(index) { (index) {
bool isLast = index + 1 == formRows.length;
return DataRow( return DataRow(
key: ValueKey("$selectedId-$index-form-row-$seed"), key: ValueKey("$selectedId-$index-form-row-$seed"),
cells: <DataCell>[ cells: <DataCell>[
DataCell( DataCell(
CellField( CellField(
keyId: "$selectedId-$index-form-k-$seed", keyId: "$selectedId-$index-form-k-$seed",
initialValue: rows[index].name, initialValue: formRows[index].name,
hintText: " Add Key", hintText: " Add Key",
onChanged: (value) { onChanged: (value) {
rows[index] = rows[index].copyWith(name: value); formRows[index] = formRows[index].copyWith(name: value);
if (isLast) formRows.add(kFormDataEmptyModel);
_onFieldChange(selectedId!); _onFieldChange(selectedId!);
}, },
colorScheme: Theme.of(context).colorScheme, colorScheme: Theme.of(context).colorScheme,
@ -80,19 +99,22 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
), ),
DataCell( DataCell(
DropdownButtonFormData( DropdownButtonFormData(
formDataType: rows[index].type, formDataType: formRows[index].type,
onChanged: (value) { onChanged: (value) {
rows[index] = rows[index].copyWith( bool hasChanged = formRows[index].type != value;
formRows[index] = formRows[index].copyWith(
type: value ?? FormDataType.text, type: value ?? FormDataType.text,
); );
rows[index] = rows[index].copyWith(value: ""); formRows[index] = formRows[index].copyWith(value: "");
setState(() {}); if (isLast && hasChanged) {
formRows.add(kFormDataEmptyModel);
}
_onFieldChange(selectedId!); _onFieldChange(selectedId!);
}, },
), ),
), ),
DataCell( DataCell(
rows[index].type == FormDataType.file formRows[index].type == FormDataType.file
? ElevatedButton.icon( ? ElevatedButton.icon(
icon: const Icon( icon: const Icon(
Icons.snippet_folder_rounded, Icons.snippet_folder_rounded,
@ -109,7 +131,7 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
if (pickedResult != null && if (pickedResult != null &&
pickedResult.files.isNotEmpty && pickedResult.files.isNotEmpty &&
pickedResult.files.first.path != null) { pickedResult.files.first.path != null) {
rows[index] = rows[index].copyWith( formRows[index] = formRows[index].copyWith(
value: pickedResult.files.first.path!, value: pickedResult.files.first.path!,
); );
setState(() {}); setState(() {});
@ -117,9 +139,9 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
} }
}, },
label: Text( label: Text(
(rows[index].type == FormDataType.file && (formRows[index].type == FormDataType.file &&
rows[index].value.isNotEmpty) formRows[index].value.isNotEmpty)
? rows[index].value.toString() ? formRows[index].value.toString()
: "Select File", : "Select File",
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: kFormDataButtonLabelTextStyle, style: kFormDataButtonLabelTextStyle,
@ -127,10 +149,12 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
) )
: CellField( : CellField(
keyId: "$selectedId-$index-form-v-$seed", keyId: "$selectedId-$index-form-v-$seed",
initialValue: rows[index].value, initialValue: formRows[index].value,
hintText: " Add Value", hintText: " Add Value",
onChanged: (value) { onChanged: (value) {
rows[index] = rows[index].copyWith(value: value); formRows[index] =
formRows[index].copyWith(value: value);
if (isLast) formRows.add(kFormDataEmptyModel);
_onFieldChange(selectedId!); _onFieldChange(selectedId!);
}, },
colorScheme: Theme.of(context).colorScheme, colorScheme: Theme.of(context).colorScheme,
@ -138,21 +162,24 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
), ),
DataCell( DataCell(
InkWell( InkWell(
onTap: isLast
? null
: () {
seed = random.nextInt(kRandMax);
if (formRows.length == 2) {
setState(() {
formRows = [
kFormDataEmptyModel,
];
});
} else {
formRows.removeAt(index);
}
_onFieldChange(selectedId!);
},
child: Theme.of(context).brightness == Brightness.dark child: Theme.of(context).brightness == Brightness.dark
? kIconRemoveDark ? kIconRemoveDark
: kIconRemoveLight, : kIconRemoveLight,
onTap: () {
seed = random.nextInt(kRandMax);
if (rows.length == 1) {
setState(() {
rows = [kFormDataEmptyModel];
});
} else {
rows.removeAt(index);
}
_onFieldChange(selectedId!);
setState(() {});
},
), ),
), ),
], ],
@ -196,9 +223,7 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
padding: const EdgeInsets.only(bottom: 30), padding: const EdgeInsets.only(bottom: 30),
child: ElevatedButton.icon( child: ElevatedButton.icon(
onPressed: () { onPressed: () {
setState(() { formRows.add(kFormDataEmptyModel);
rows.add(kFormDataEmptyModel);
});
_onFieldChange(selectedId!); _onFieldChange(selectedId!);
}, },
icon: const Icon(Icons.add), icon: const Icon(Icons.add),
@ -212,11 +237,4 @@ class _FormDataBodyState extends ConsumerState<FormDataWidget> {
], ],
); );
} }
void _onFieldChange(String selectedId) {
ref.read(collectionStateNotifierProvider.notifier).update(
selectedId,
requestFormDataList: rows,
);
}
} }

View File

@ -15,10 +15,10 @@ class EditRequestHeaders extends ConsumerStatefulWidget {
} }
class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> { class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
final random = Random.secure();
late List<NameValueModel> rows;
late List<bool> isRowEnabledList;
late int seed; late int seed;
final random = Random.secure();
late List<NameValueModel> headerRows;
late List<bool> isRowEnabledList;
@override @override
void initState() { void initState() {
@ -29,8 +29,9 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
void _onFieldChange(String selectedId) { void _onFieldChange(String selectedId) {
ref.read(collectionStateNotifierProvider.notifier).update( ref.read(collectionStateNotifierProvider.notifier).update(
selectedId, selectedId,
requestHeaders: rows, requestHeaders: headerRows.sublist(0, headerRows.length - 1),
isHeaderEnabledList: isRowEnabledList, isHeaderEnabledList:
isRowEnabledList.sublist(0, headerRows.length - 1),
); );
} }
@ -40,14 +41,16 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
ref.watch(selectedRequestModelProvider ref.watch(selectedRequestModelProvider
.select((value) => value?.requestHeaders?.length)); .select((value) => value?.requestHeaders?.length));
var rH = ref.read(selectedRequestModelProvider)?.requestHeaders; var rH = ref.read(selectedRequestModelProvider)?.requestHeaders;
rows = (rH == null || rH.isEmpty) bool isHeadersEmpty = rH == null || rH.isEmpty;
headerRows = isHeadersEmpty
? [ ? [
kNameValueEmptyModel, kNameValueEmptyModel,
] ]
: rH; : rH + [kNameValueEmptyModel];
isRowEnabledList = isRowEnabledList =
ref.read(selectedRequestModelProvider)?.isHeaderEnabledList ?? ref.read(selectedRequestModelProvider)?.isHeaderEnabledList ??
List.filled(rows.length, true, growable: true); List.filled(rH?.length ?? 0, true, growable: true);
isRowEnabledList.add(false);
List<DataColumn> columns = const [ List<DataColumn> columns = const [
DataColumn2( DataColumn2(
@ -71,8 +74,9 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
]; ];
List<DataRow> dataRows = List<DataRow>.generate( List<DataRow> dataRows = List<DataRow>.generate(
rows.length, headerRows.length,
(index) { (index) {
bool isLast = index + 1 == headerRows.length;
return DataRow( return DataRow(
key: ValueKey("$selectedId-$index-headers-row-$seed"), key: ValueKey("$selectedId-$index-headers-row-$seed"),
cells: <DataCell>[ cells: <DataCell>[
@ -80,22 +84,29 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
CheckBox( CheckBox(
keyId: "$selectedId-$index-headers-c-$seed", keyId: "$selectedId-$index-headers-c-$seed",
value: isRowEnabledList[index], value: isRowEnabledList[index],
onChanged: (value) { onChanged: isLast
setState(() { ? null
isRowEnabledList[index] = value!; : (value) {
}); setState(() {
_onFieldChange(selectedId!); isRowEnabledList[index] = value!;
}, });
_onFieldChange(selectedId!);
},
colorScheme: Theme.of(context).colorScheme, colorScheme: Theme.of(context).colorScheme,
), ),
), ),
DataCell( DataCell(
HeaderField( HeaderField(
keyId: "$selectedId-$index-headers-k-$seed", keyId: "$selectedId-$index-headers-k-$seed",
initialValue: rows[index].name, initialValue: headerRows[index].name,
hintText: "Add Header Name", hintText: "Add Header Name",
onChanged: (value) { onChanged: (value) {
rows[index] = rows[index].copyWith(name: value); headerRows[index] = headerRows[index].copyWith(name: value);
if (isLast) {
isRowEnabledList[index] = true;
headerRows.add(kNameValueEmptyModel);
isRowEnabledList.add(false);
}
_onFieldChange(selectedId!); _onFieldChange(selectedId!);
}, },
colorScheme: Theme.of(context).colorScheme, colorScheme: Theme.of(context).colorScheme,
@ -110,10 +121,15 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
DataCell( DataCell(
CellField( CellField(
keyId: "$selectedId-$index-headers-v-$seed", keyId: "$selectedId-$index-headers-v-$seed",
initialValue: rows[index].value, initialValue: headerRows[index].value,
hintText: " Add Header Value", hintText: " Add Header Value",
onChanged: (value) { onChanged: (value) {
rows[index] = rows[index].copyWith(value: value); headerRows[index] = headerRows[index].copyWith(value: value);
if (isLast) {
isRowEnabledList[index] = true;
headerRows.add(kNameValueEmptyModel);
isRowEnabledList.add(false);
}
_onFieldChange(selectedId!); _onFieldChange(selectedId!);
}, },
colorScheme: Theme.of(context).colorScheme, colorScheme: Theme.of(context).colorScheme,
@ -121,24 +137,26 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
), ),
DataCell( DataCell(
InkWell( InkWell(
onTap: isLast
? null
: () {
seed = random.nextInt(kRandMax);
if (headerRows.length == 2) {
setState(() {
headerRows = [
kNameValueEmptyModel,
];
isRowEnabledList = [false];
});
} else {
headerRows.removeAt(index);
isRowEnabledList.removeAt(index);
}
_onFieldChange(selectedId!);
},
child: Theme.of(context).brightness == Brightness.dark child: Theme.of(context).brightness == Brightness.dark
? kIconRemoveDark ? kIconRemoveDark
: kIconRemoveLight, : kIconRemoveLight,
onTap: () {
seed = random.nextInt(kRandMax);
if (rows.length == 1) {
setState(() {
rows = [
kNameValueEmptyModel,
];
isRowEnabledList = [true];
});
} else {
rows.removeAt(index);
isRowEnabledList.removeAt(index);
}
_onFieldChange(selectedId!);
},
), ),
), ),
], ],
@ -182,8 +200,8 @@ class EditRequestHeadersState extends ConsumerState<EditRequestHeaders> {
padding: const EdgeInsets.only(bottom: 30), padding: const EdgeInsets.only(bottom: 30),
child: ElevatedButton.icon( child: ElevatedButton.icon(
onPressed: () { onPressed: () {
rows.add(kNameValueEmptyModel); headerRows.add(kNameValueEmptyModel);
isRowEnabledList.add(true); isRowEnabledList.add(false);
_onFieldChange(selectedId!); _onFieldChange(selectedId!);
}, },
icon: const Icon(Icons.add), icon: const Icon(Icons.add),

View File

@ -16,10 +16,10 @@ class EditRequestURLParams extends ConsumerStatefulWidget {
} }
class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> { class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
final random = Random.secure();
late List<NameValueModel> rows;
late List<bool> isRowEnabledList;
late int seed; late int seed;
final random = Random.secure();
late List<NameValueModel> paramRows;
late List<bool> isRowEnabledList;
@override @override
void initState() { void initState() {
@ -30,8 +30,8 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
void _onFieldChange(String selectedId) { void _onFieldChange(String selectedId) {
ref.read(collectionStateNotifierProvider.notifier).update( ref.read(collectionStateNotifierProvider.notifier).update(
selectedId, selectedId,
requestParams: rows, requestParams: paramRows.sublist(0, paramRows.length - 1),
isParamEnabledList: isRowEnabledList, isParamEnabledList: isRowEnabledList.sublist(0, paramRows.length - 1),
); );
} }
@ -41,14 +41,16 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
ref.watch(selectedRequestModelProvider ref.watch(selectedRequestModelProvider
.select((value) => value?.requestParams?.length)); .select((value) => value?.requestParams?.length));
var rP = ref.read(selectedRequestModelProvider)?.requestParams; var rP = ref.read(selectedRequestModelProvider)?.requestParams;
rows = (rP == null || rP.isEmpty) bool isParamsEmpty = rP == null || rP.isEmpty;
paramRows = isParamsEmpty
? [ ? [
kNameValueEmptyModel, kNameValueEmptyModel,
] ]
: rP; : rP + [kNameValueEmptyModel];
isRowEnabledList = isRowEnabledList =
ref.read(selectedRequestModelProvider)?.isParamEnabledList ?? ref.read(selectedRequestModelProvider)?.isParamEnabledList ??
List.filled(rows.length, true, growable: true); List.filled(rP?.length ?? 0, true, growable: true);
isRowEnabledList.add(false);
List<DataColumn> columns = const [ List<DataColumn> columns = const [
DataColumn2( DataColumn2(
@ -72,8 +74,9 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
]; ];
List<DataRow> dataRows = List<DataRow>.generate( List<DataRow> dataRows = List<DataRow>.generate(
rows.length, paramRows.length,
(index) { (index) {
bool isLast = index + 1 == paramRows.length;
return DataRow( return DataRow(
key: ValueKey("$selectedId-$index-params-row-$seed"), key: ValueKey("$selectedId-$index-params-row-$seed"),
cells: <DataCell>[ cells: <DataCell>[
@ -81,22 +84,29 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
CheckBox( CheckBox(
keyId: "$selectedId-$index-params-c-$seed", keyId: "$selectedId-$index-params-c-$seed",
value: isRowEnabledList[index], value: isRowEnabledList[index],
onChanged: (value) { onChanged: isLast
setState(() { ? null
isRowEnabledList[index] = value!; : (value) {
}); setState(() {
_onFieldChange(selectedId!); isRowEnabledList[index] = value!;
}, });
_onFieldChange(selectedId!);
},
colorScheme: Theme.of(context).colorScheme, colorScheme: Theme.of(context).colorScheme,
), ),
), ),
DataCell( DataCell(
CellField( CellField(
keyId: "$selectedId-$index-params-k-$seed", keyId: "$selectedId-$index-params-k-$seed",
initialValue: rows[index].name, initialValue: paramRows[index].name,
hintText: "Add URL Parameter", hintText: "Add URL Parameter",
onChanged: (value) { onChanged: (value) {
rows[index] = rows[index].copyWith(name: value); paramRows[index] = paramRows[index].copyWith(name: value);
if (isLast) {
isRowEnabledList[index] = true;
paramRows.add(kNameValueEmptyModel);
isRowEnabledList.add(false);
}
_onFieldChange(selectedId!); _onFieldChange(selectedId!);
}, },
colorScheme: Theme.of(context).colorScheme, colorScheme: Theme.of(context).colorScheme,
@ -111,10 +121,15 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
DataCell( DataCell(
CellField( CellField(
keyId: "$selectedId-$index-params-v-$seed", keyId: "$selectedId-$index-params-v-$seed",
initialValue: rows[index].value, initialValue: paramRows[index].value,
hintText: "Add Value", hintText: "Add Value",
onChanged: (value) { onChanged: (value) {
rows[index] = rows[index].copyWith(value: value); paramRows[index] = paramRows[index].copyWith(value: value);
if (isLast) {
isRowEnabledList[index] = true;
paramRows.add(kNameValueEmptyModel);
isRowEnabledList.add(false);
}
_onFieldChange(selectedId!); _onFieldChange(selectedId!);
}, },
colorScheme: Theme.of(context).colorScheme, colorScheme: Theme.of(context).colorScheme,
@ -122,24 +137,26 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
), ),
DataCell( DataCell(
InkWell( InkWell(
onTap: isLast
? null
: () {
seed = random.nextInt(kRandMax);
if (paramRows.length == 2) {
setState(() {
paramRows = [
kNameValueEmptyModel,
];
isRowEnabledList = [false];
});
} else {
paramRows.removeAt(index);
isRowEnabledList.removeAt(index);
}
_onFieldChange(selectedId!);
},
child: Theme.of(context).brightness == Brightness.dark child: Theme.of(context).brightness == Brightness.dark
? kIconRemoveDark ? kIconRemoveDark
: kIconRemoveLight, : kIconRemoveLight,
onTap: () {
seed = random.nextInt(kRandMax);
if (rows.length == 1) {
setState(() {
rows = [
kNameValueEmptyModel,
];
isRowEnabledList = [true];
});
} else {
rows.removeAt(index);
isRowEnabledList.removeAt(index);
}
_onFieldChange(selectedId!);
},
), ),
), ),
], ],
@ -184,8 +201,8 @@ class EditRequestURLParamsState extends ConsumerState<EditRequestURLParams> {
padding: const EdgeInsets.only(bottom: 30), padding: const EdgeInsets.only(bottom: 30),
child: ElevatedButton.icon( child: ElevatedButton.icon(
onPressed: () { onPressed: () {
rows.add(kNameValueEmptyModel); paramRows.add(kNameValueEmptyModel);
isRowEnabledList.add(true); isRowEnabledList.add(false);
_onFieldChange(selectedId!); _onFieldChange(selectedId!);
}, },
icon: const Icon(Icons.add), icon: const Icon(Icons.add),

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
class CheckBox extends StatelessWidget { class CheckBox extends StatelessWidget {
final String keyId; final String keyId;
final bool value; final bool value;
final ValueChanged<bool?> onChanged; final ValueChanged<bool?>? onChanged;
final ColorScheme? colorScheme; final ColorScheme? colorScheme;
const CheckBox({ const CheckBox({
super.key, super.key,

View File

@ -16,7 +16,7 @@ class IntroMessage extends StatelessWidget {
late final String version; late final String version;
Future<void> introData() async { Future<void> introData() async {
text = await rootBundle.loadString('assets/intro.md'); text = await rootBundle.loadString(kAssetIntroMd);
version = (await PackageInfo.fromPlatform()).version; version = (await PackageInfo.fromPlatform()).version;
} }

View File

@ -0,0 +1,63 @@
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
import '../consts.dart';
class OverlayWidgetTemplate {
OverlayEntry? _overlay;
BuildContext context;
OverlayState? _overlayState;
OverlayWidgetTemplate({required this.context}) {
_overlayState = Overlay.of(context);
}
void show({required Widget widget}) {
if (_overlay == null) {
_overlay = OverlayEntry(
// replace with your own layout
builder: (context) => ColoredBox(
color: kColorBlack.withOpacity(kOverlayBackgroundOpacity),
child: widget),
);
_overlayState!.insert(_overlay!);
}
}
void hide() {
if (_overlay != null) {
_overlay?.remove();
_overlay = null;
}
}
}
class SavingOverlay extends StatelessWidget {
final bool saveCompleted;
const SavingOverlay({super.key, required this.saveCompleted});
@override
Widget build(BuildContext context) {
return Center(
child: Card(
child: Padding(
padding: kPh60v60,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Lottie.asset(
saveCompleted ? kAssetSavedLottie : kAssetSavingLottie,
width: 100,
height: 100),
kHSpacer20,
Text(
saveCompleted ? kLabelSaved : kLabelSaving,
style: const TextStyle(
fontSize: kDefaultFontSize,
),
)
],
),
),
),
);
}
}

View File

@ -42,7 +42,7 @@ class SendingWidget extends StatelessWidget {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Lottie.asset("assets/sending.json"), Lottie.asset(kAssetSendingLottie),
], ],
), ),
); );

View File

@ -12,6 +12,7 @@ export 'intro_message.dart';
export 'json_previewer.dart'; export 'json_previewer.dart';
export 'markdown.dart'; export 'markdown.dart';
export 'menus.dart'; export 'menus.dart';
export 'overlay_widget.dart';
export 'previewer.dart'; export 'previewer.dart';
export 'request_widgets.dart'; export 'request_widgets.dart';
export 'response_widgets.dart'; export 'response_widgets.dart';

View File

@ -0,0 +1,58 @@
import 'package:apidash/consts.dart';
import 'package:apidash/widgets/overlay_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:lottie/lottie.dart';
void main() {
testWidgets('OverlayWidgetTemplate Test', (WidgetTester tester) async {
late OverlayWidgetTemplate overlayWidget;
await tester.pumpWidget(
MaterialApp(
home: Builder(
builder: (BuildContext context) {
overlayWidget = OverlayWidgetTemplate(context: context);
return Container(); // Return any widget here, as OverlayWidgetTemplate doesn't return a widget
},
),
),
);
overlayWidget.show(widget: const Text('Test'));
await tester.pump();
expect(find.text('Test'), findsOneWidget);
overlayWidget.hide();
await tester.pump();
expect(find.text('Test'), findsNothing);
});
testWidgets('SavingOverlay Test', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
home: Scaffold(
body: SavingOverlay(
saveCompleted: false,
),
),
),
);
expect(find.byType(Card), findsOneWidget);
expect(find.byType(Lottie), findsOneWidget);
expect(find.text(kLabelSaving), findsOneWidget);
await tester.pumpWidget(
const MaterialApp(
home: Scaffold(
body: SavingOverlay(
saveCompleted: true,
),
),
),
);
expect(find.byType(Card), findsOneWidget);
expect(find.byType(Lottie), findsOneWidget);
expect(find.text(kLabelSaved), findsOneWidget);
});
}