Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 22 additions & 51 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import 'package:flutter/material.dart';
import 'package:multi_sort/SortableButton.dart';
import "package:multi_sort/multi_sort.dart";

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: ExampleApp(),
);
}
Expand All @@ -22,82 +17,70 @@ class MyApp extends StatelessWidget {
class ExampleApp extends StatefulWidget {
ExampleApp({Key key}) : super(key: key);

@override
_ExampleAppState createState() => _ExampleAppState();
}

/// Class of Items
class Items {
class Items implements Sortable {
String name;
int ram;
int price;
int storage;
Items(this.name, this.ram, this.price, this.storage);

///Mapping the properties
Map<String, dynamic> _toMap() {
Map<String, Comparable> sortableFields() {
return {'name': name, 'price': price, 'ram': ram, 'storage': storage};
}

///get function to get the properties of Item
dynamic get(String propertyName) {
var _mapRep = _toMap();
if (_mapRep.containsKey(propertyName)) {
return _mapRep[propertyName];
}
throw ArgumentError('propery not found');
}
}

class _ExampleAppState extends State<ExampleApp> {
//List of Items
List<Items> items = [
Items("real me 6", 6, 18999, 128),
var data = [
Items("real me 6", 6, 18999, 1),
Items("real me 6", 8, 19999, 128),
Items("real Note 8", 7, 16999, 128),
Items("oppo a9", 4, 13999, 128),
Items("oppo a9", 4, 13999, 64),
Items("real me 6 pro", 6, 17999, 64),
Items("Oppo 5as", 2, 8999, 32),
Items("Real me 5i", 4, 10999, 64),
Items("Poco x2", 6, 18500, 128),
];
// Temp List for sorting
List<Items> sortingList = [];
//Criteria List
List<bool> criteria = [false, false];
//prefrrence List
List<String> preferrence = ['ram', 'storage'];

@override
void initState() {
// TODO: implement initState
super.initState();
var sortedFields = <SortField>[];

void setSortedFields(List<SortField> sortedFields) {
setState(() {
sortingList = items;
this.sortedFields = sortedFields;
this.data = data.multisort(sortedFields);
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sort List Example"),
),
body: Column(
children: [
_buttons(),
Row(children: [
SortableButton(sortedFields, SortField('name'), setSortedFields),
SortableButton(sortedFields, SortField('price'), setSortedFields),
SortableButton(sortedFields, SortField('ram'), setSortedFields),
SortableButton(sortedFields, SortField('storage'), setSortedFields),
]),
ListView.builder(
shrinkWrap: true,
itemCount: sortingList.length,
itemCount: data.length,
itemBuilder: (BuildContext context, int i) {
return Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(sortingList[i].name),
Text(sortingList[i].price.toString()),
Text(sortingList[i].ram.toString()),
Text(sortingList[i].storage.toString()),
Text(data[i].name),
Text(data[i].price.toString()),
Text(data[i].ram.toString()),
Text(data[i].storage.toString()),
],
),
);
Expand All @@ -106,16 +89,4 @@ class _ExampleAppState extends State<ExampleApp> {
),
);
}

Widget _buttons() {
return RaisedButton(
onPressed: () {
setState(() {
///Sorting using MultiSort
sortingList.multisort(criteria, preferrence);
});
},
child: Text('Sort by preferrence'),
);
}
}
74 changes: 74 additions & 0 deletions lib/SortableButton.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import 'package:dartx/dartx.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';

import 'multi_sort.dart';

/// A button to go with multi-sort to toggle sorting on multiple fields
class SortableButton extends StatelessWidget {
/// The current list of sorted fields
final List<SortField> sortedFields;

/// This field
final SortField field;

/// The text for the button label
final String text;

/// A callback to set the altered sortedFields list
///
/// '''void setSortedFields(List<SortField> sortedFields) {
// setState(() {
// this.sortedFields = sortedFields;
// this.data = data.multisort(sortedFields);
// });
// }'''
final void Function(List<SortField>) onPressed;

SortableButton(this.sortedFields, this.field, this.onPressed, {this.text});

Widget build(BuildContext context) {
SortField thisSortedField;
int index;

sortedFields.forEachIndexed((e, i) {
if (e.fieldName == field.fieldName) {
index = i;
thisSortedField = e;
}
});

return TextButton(
onPressed: () {
var newSortedFields = <SortField>[];

if (thisSortedField == null) //
newSortedFields = [...sortedFields, field];
else {
if (thisSortedField.isAscending) //
newSortedFields = sortedFields.map((e) => e.fieldName != thisSortedField.fieldName ? e : SortField(e.fieldName, isAscending: false)).toList();
else
newSortedFields = sortedFields.where((e) => e.fieldName != thisSortedField.fieldName).toList();
}

onPressed(newSortedFields);
},
child: Row(
children: [
if (thisSortedField != null) //
...[
Icon(
thisSortedField.isAscending ? FontAwesomeIcons.angleUp : FontAwesomeIcons.angleDown,
size: 15,
),
Text(
index.toString(),
textScaleFactor: 0.6,
),
],
Text(this.text ?? field.fieldName),
],
),
);
}
}
58 changes: 42 additions & 16 deletions lib/multi_sort.dart
Original file line number Diff line number Diff line change
@@ -1,34 +1,60 @@
library multi_sort;

extension MultiSort on List {
multisort(List<bool> criteria, dynamic preferrence) {
if (preferrence.length == 0 || criteria.length == 0 || this.length == 0)
return this;
if (preferrence.length != criteria.length) {
print('Criteria length is not equal to preferrence');
///get function to get the properties of Item
Comparable getComparableField(String propertyName, Sortable sortable) {
var _mapRep = sortable.sortableFields();
if (_mapRep.containsKey(propertyName)) {
return _mapRep[propertyName];
}
throw ArgumentError('propery not found');
}

abstract class Sortable {
///A list of strings and their textual ids eg
///
/// {'name': name, 'price': price, 'ram': ram, 'storage': storage};
Map<String, Comparable> sortableFields();
}

class SortField {
final String fieldName;
final bool isAscending;

SortField(this.fieldName, {this.isAscending = true});
}

extension MultiSort on List<Sortable> {
List<Sortable> multisort(List<SortField> sortedFields) {
if (sortedFields.length == 0) //
return this;
}

int compare(int i, dynamic a, dynamic b) {
if (a.get(preferrence[i]) == b.get(preferrence[i]))
return 0;
else if (a.get(preferrence[i]) > b.get(preferrence[i]))
return criteria[i] ? 1 : -1;
else
return criteria[i] ? -1 : 1;
int compare(int i, Sortable a, Sortable b) {
var valueA = getComparableField(sortedFields[i].fieldName, a);
var valueB = getComparableField(sortedFields[i].fieldName, b);

var result = valueA.compareTo(valueB);

if (!sortedFields[i].isAscending) //
return result * -1;

return result;
}

int sortall(a, b) {
int i = 0;
int result;
while (i < preferrence.length) {
while (i < sortedFields.length) {
result = compare(i, a, b);
if (result != 0) break;
i++;
}
return result;
}

this.sort((a, b) => sortall(a, b));
final list = this.toList();

list.sort((a, b) => sortall(a, b));

return list;
}
}
2 changes: 2 additions & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ environment:
dependencies:
flutter:
sdk: flutter
dartx: ^0.6.0
font_awesome_flutter: ^9.0.0

dev_dependencies:
flutter_test:
Expand Down
82 changes: 82 additions & 0 deletions test/multisort_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//flutter test --plain-name=LessonSplitter

import 'package:flutter_test/flutter_test.dart';
import 'package:multi_sort/multi_sort.dart';

/// Class of Items
class Items implements Sortable {
String name;
int ram;
Items(this.name, this.ram);

String toString() => //
"name: ${this.name}, ram: ${this.ram}";

Map<String, Comparable> sortableFields() => //
{
'name': name,
'ram': ram,
};
}

void main() {
group("multiSort", () {
// List<Items> unsorted;

var unsorted = [
Items("b", 1),
Items("b", 128),
Items("a", 64),
];

// setUp(() {
// unsorted = [
// Items("b", 1),
// Items("b", 128),
// Items("a", 64),
// ];
// });

test("two asc", () {
var sortedFields = [
SortField('ram'),
SortField('name'),
];
var sorted = unsorted.multisort(sortedFields);
var expected = [
Items("b", 1),
Items("a", 64),
Items("b", 128),
];

expect(sorted.toString(), expected.toString());
});

test("two asc & desc", () {
var sortedFields = [
SortField('name'),
SortField('ram', isAscending: false),
];
var sorted = unsorted.multisort(sortedFields);
var expected = [
Items("a", 64),
Items("b", 128),
Items("b", 1),
];

expect(sorted.toString(), expected.toString());
});

test("sort set to null", () {
var sortedFields = <SortField>[];
var sorted = unsorted.multisort(sortedFields);
var expected = [
Items("b", 1),
Items("b", 128),
Items("a", 64),
];

expect(sorted.toString(), expected.toString());
});
});
}