mirror of
https://github.com/rzuasti/oott.git
synced 2026-07-08 19:21:54 +02:00
Shrink notification and device list page sizes on phones
On phone-width layouts (< Breakpoints.medium) the notification and device lists now request fewer items per page so the list and its pagination bar fit on screen together on common current phones. Notifications use 4 items and devices 6 on phones; wider layouts keep 5 and 10 respectively. The initial fetch is deferred to didChangeDependencies so the page size can read the screen width from MediaQuery. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
8b8fa5ce89
commit
0a899b7890
@@ -25,7 +25,7 @@
|
|||||||
## Frontend
|
## Frontend
|
||||||
|
|
||||||
- [x] Mobile - Implement pull to refresh on the notifications and devices list
|
- [x] Mobile - Implement pull to refresh on the notifications and devices list
|
||||||
- [ ] Mobile - reduce lists length (# of items) so they fit on a phone in one screen (use iPhone latest gen and Google phone latest gen)
|
- [x] Mobile - reduce lists length (# of items) so they fit on a phone in one screen (use iPhone latest gen and Google phone latest gen)
|
||||||
- [ ] Mobile - In the devices list the filters and sort buttons overlap (dont fit in the screen)
|
- [ ] Mobile - In the devices list the filters and sort buttons overlap (dont fit in the screen)
|
||||||
- [ ] When changing pages (either list) the items should change to placeholders while loading
|
- [ ] When changing pages (either list) the items should change to placeholders while loading
|
||||||
- [ ] The notifications list should not refresh coldly every time. It should add/remove notifications with an animation as if a stack
|
- [ ] The notifications list should not refresh coldly every time. It should add/remove notifications with an animation as if a stack
|
||||||
|
|||||||
@@ -17,7 +17,11 @@ import 'device_list_filter.dart';
|
|||||||
import 'device_list_rows.dart';
|
import 'device_list_rows.dart';
|
||||||
import 'device_list_sort.dart';
|
import 'device_list_sort.dart';
|
||||||
|
|
||||||
const _pageSize = 10;
|
// Phones show fewer devices so the list and its pagination controls fit on
|
||||||
|
// screen at once on the common current phones (e.g. iPhone 15, Pixel 8); the
|
||||||
|
// wider table layout has the vertical room for a full page.
|
||||||
|
const _phonePageSize = 6;
|
||||||
|
const _widePageSize = 10;
|
||||||
|
|
||||||
class DeviceList extends StatefulWidget {
|
class DeviceList extends StatefulWidget {
|
||||||
const DeviceList({super.key});
|
const DeviceList({super.key});
|
||||||
@@ -40,14 +44,18 @@ class _DeviceListState extends State<DeviceList> with RouteAware {
|
|||||||
|
|
||||||
int _currentPage = 0;
|
int _currentPage = 0;
|
||||||
bool _hasNextPage = false;
|
bool _hasNextPage = false;
|
||||||
|
bool _didInitialFetch = false;
|
||||||
CancelToken? _fetchToken;
|
CancelToken? _fetchToken;
|
||||||
final ScrollController _scrollController = ScrollController();
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
|
||||||
|
int get _pageSize => MediaQuery.sizeOf(context).width < Breakpoints.medium
|
||||||
|
? _phonePageSize
|
||||||
|
: _widePageSize;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_ownerController.addListener(_onOwnerChanged);
|
_ownerController.addListener(_onOwnerChanged);
|
||||||
_fetchPage(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -57,6 +65,12 @@ class _DeviceListState extends State<DeviceList> with RouteAware {
|
|||||||
if (route is ModalRoute<void>) {
|
if (route is ModalRoute<void>) {
|
||||||
routeObserver.subscribe(this, route);
|
routeObserver.subscribe(this, route);
|
||||||
}
|
}
|
||||||
|
// Deferred from initState so the page size can read the screen width from
|
||||||
|
// MediaQuery, which is only available once dependencies are in place.
|
||||||
|
if (!_didInitialFetch) {
|
||||||
|
_didInitialFetch = true;
|
||||||
|
_fetchPage(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -14,7 +14,11 @@ import '../widgets/pagination_bar.dart';
|
|||||||
import '../widgets/skeleton.dart';
|
import '../widgets/skeleton.dart';
|
||||||
import 'notification_card.dart';
|
import 'notification_card.dart';
|
||||||
|
|
||||||
const _pageSize = 5;
|
// Phones show fewer notifications so the list and its pagination controls fit
|
||||||
|
// on screen at once on the common current phones (e.g. iPhone 15, Pixel 8);
|
||||||
|
// wider layouts have the vertical room for a couple more.
|
||||||
|
const _phonePageSize = 4;
|
||||||
|
const _widePageSize = 5;
|
||||||
|
|
||||||
enum _NotificationFilter {
|
enum _NotificationFilter {
|
||||||
newOnly('New'),
|
newOnly('New'),
|
||||||
@@ -47,8 +51,13 @@ class _NotificationsListState extends State<NotificationsList>
|
|||||||
Timer? _notificationTimer;
|
Timer? _notificationTimer;
|
||||||
|
|
||||||
int _currentPage = 0;
|
int _currentPage = 0;
|
||||||
|
bool _didInitialFetch = false;
|
||||||
List<oott_model.Notification> _items = [];
|
List<oott_model.Notification> _items = [];
|
||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
|
|
||||||
|
int get _pageSize => MediaQuery.sizeOf(context).width < Breakpoints.medium
|
||||||
|
? _phonePageSize
|
||||||
|
: _widePageSize;
|
||||||
bool _hasNextPage = false;
|
bool _hasNextPage = false;
|
||||||
String? _error;
|
String? _error;
|
||||||
CancelToken? _fetchToken;
|
CancelToken? _fetchToken;
|
||||||
@@ -58,7 +67,6 @@ class _NotificationsListState extends State<NotificationsList>
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
_fetchPage(0);
|
|
||||||
_startTimer();
|
_startTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,6 +77,12 @@ class _NotificationsListState extends State<NotificationsList>
|
|||||||
if (route is ModalRoute<void>) {
|
if (route is ModalRoute<void>) {
|
||||||
routeObserver.subscribe(this, route);
|
routeObserver.subscribe(this, route);
|
||||||
}
|
}
|
||||||
|
// Deferred from initState so the page size can read the screen width from
|
||||||
|
// MediaQuery, which is only available once dependencies are in place.
|
||||||
|
if (!_didInitialFetch) {
|
||||||
|
_didInitialFetch = true;
|
||||||
|
_fetchPage(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -62,19 +62,21 @@ void main() {
|
|||||||
tester.view.devicePixelRatio = 1.0;
|
tester.view.devicePixelRatio = 1.0;
|
||||||
addTearDown(tester.view.resetPhysicalSize);
|
addTearDown(tester.view.resetPhysicalSize);
|
||||||
|
|
||||||
|
// The 400px-wide viewport above is a phone, so the list uses the smaller
|
||||||
|
// phone page size of 4 (requesting page_limit 5 to detect a next page).
|
||||||
List<Map<String, dynamic>> page(int firstId) => List.generate(
|
List<Map<String, dynamic>> page(int firstId) => List.generate(
|
||||||
6,
|
5,
|
||||||
(i) => notificationJson(id: firstId + i, title: 'Item ${firstId + i}'),
|
(i) => notificationJson(id: firstId + i, title: 'Item ${firstId + i}'),
|
||||||
);
|
);
|
||||||
adapter.onGet(
|
adapter.onGet(
|
||||||
'/notifications',
|
'/notifications',
|
||||||
(server) => server.reply(200, page(1)),
|
(server) => server.reply(200, page(1)),
|
||||||
queryParameters: {'is_new': true, 'page_offset': 0, 'page_limit': 6},
|
queryParameters: {'is_new': true, 'page_offset': 0, 'page_limit': 5},
|
||||||
);
|
);
|
||||||
adapter.onGet(
|
adapter.onGet(
|
||||||
'/notifications',
|
'/notifications',
|
||||||
(server) => server.reply(200, page(7)),
|
(server) => server.reply(200, page(6)),
|
||||||
queryParameters: {'is_new': true, 'page_offset': 5, 'page_limit': 6},
|
queryParameters: {'is_new': true, 'page_offset': 4, 'page_limit': 5},
|
||||||
);
|
);
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
@@ -119,7 +121,7 @@ void main() {
|
|||||||
adapter.onGet(
|
adapter.onGet(
|
||||||
'/notifications',
|
'/notifications',
|
||||||
(server) => server.reply(200, items),
|
(server) => server.reply(200, items),
|
||||||
queryParameters: {'is_new': true, 'page_offset': 0, 'page_limit': 6},
|
queryParameters: {'is_new': true, 'page_offset': 0, 'page_limit': 5},
|
||||||
);
|
);
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
|
|||||||
Reference in New Issue
Block a user