Skip to content

Commit

Permalink
start work on proper medium layouts, linting, and logging
Browse files Browse the repository at this point in the history
  • Loading branch information
mootw committed Oct 13, 2023
1 parent dd40589 commit a16abdf
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 99 deletions.
4 changes: 4 additions & 0 deletions app/lib/helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import 'dart:math';
// this means that the unfolded z fold could overflow slightly...
// but the intention is to accomodate larger screens sooo

// https://m3.material.io/foundations/layout/applying-layout/medium
bool isLargeDevice(BuildContext context) => MediaQuery.of(context).size.width > 600;


//Theme data
const primaryColor = Color.fromARGB(255, 49, 219, 43);
final darkScheme =
Expand Down
160 changes: 85 additions & 75 deletions app/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';

import 'package:app/providers/data_provider.dart';
import 'package:app/helpers.dart';
Expand Down Expand Up @@ -68,7 +67,6 @@ class MyHomePage extends StatefulWidget {
}

class _MyHomePageState extends State<MyHomePage> {

int _currentPageIndex = 0;

@override
Expand Down Expand Up @@ -103,6 +101,8 @@ class _MyHomePageState extends State<MyHomePage> {

final nextMatch = data.event.nextMatch;

final largeDevice = isLargeDevice(context);

return Scaffold(
appBar: AppBar(
bottom: const LoadOrErrorStatusBar(),
Expand All @@ -123,22 +123,57 @@ class _MyHomePageState extends State<MyHomePage> {
icon: const Icon(Icons.search))
],
),
body: [
AllMatchesPage(
// 10/10 hack to make the widget re-scroll to the correct spot on load
// this will force it to scroll whenever the matches length changes
// we could add another value here to make it scroll on other changes too
key: Key(data.event.matches.length.toString()),
scrollPosition: nextMatch == null
? null
: (data.event.matches.values.toList().indexOf(nextMatch) *
matchCardHeight) -
(matchCardHeight * 2),
),
const TeamGridList(showEditButton: true),
const AnalysisPage(),
const DocumentationScreen(),
][_currentPageIndex],
body: Row(children: [
if (largeDevice)
NavigationRail(
backgroundColor: Theme.of(context).bottomNavigationBarTheme.backgroundColor,
labelType: NavigationRailLabelType.all,
onDestinationSelected: (int index) {
setState(() {
_currentPageIndex = index;
});
},
destinations: const [
NavigationRailDestination(
selectedIcon: Icon(Icons.calendar_today),
icon: Icon(Icons.calendar_today_outlined),
label: Text('Schedule'),
),
NavigationRailDestination(
selectedIcon: Icon(Icons.people),
icon: Icon(Icons.people_alt_outlined),
label: Text('Teams'),
),
NavigationRailDestination(
selectedIcon: Icon(Icons.analytics),
icon: Icon(Icons.analytics_outlined),
label: Text('Analysis'),
),
NavigationRailDestination(
selectedIcon: Icon(Icons.book),
icon: Icon(Icons.book_outlined),
label: Text('Docs'),
),
], selectedIndex: _currentPageIndex),
Expanded(
child: [
AllMatchesPage(
// 10/10 hack to make the widget re-scroll to the correct spot on load
// this will force it to scroll whenever the matches length changes
// we could add another value here to make it scroll on other changes too
key: Key(data.event.matches.length.toString()),
scrollPosition: nextMatch == null
? null
: (data.event.matches.values.toList().indexOf(nextMatch) *
matchCardHeight) -
(matchCardHeight * 2),
),
const TeamGridList(showEditButton: true),
const AnalysisPage(),
const DocumentationScreen(),
][_currentPageIndex],
),
]),
drawer: Drawer(
child: ListView(children: [
ListTile(
Expand Down Expand Up @@ -226,65 +261,40 @@ class _MyHomePageState extends State<MyHomePage> {
},
icon: const Icon(Icons.edit)),
),
ListTile(
title: const Text("Set Pit Map Image"),
trailing: IconButton(
onPressed: () async {
final identity = context.read<IdentityProvider>().identity;

String result;
//TAKE PHOTO
try {
final photo = await pickOrTakeImageDialog(context);
if (photo != null) {
Uint8List bytes = await photo.readAsBytes();
result = base64Encode(bytes);
Patch patch = Patch(
identity: identity,
time: DateTime.now(),
path: Patch.buildPath(['pitmap']),
value: result);
//Save the scouting results to the server!!
await data.submitPatch(patch);
}
} catch (e, s) {
Logger.root.severe("Error taking image from device", e, s);
}
},
icon: const Icon(Icons.camera_alt)),
),
]),
),
bottomNavigationBar: NavigationBar(
onDestinationSelected: (int index) {
setState(() {
_currentPageIndex = index;
});
},
selectedIndex: _currentPageIndex,
destinations: const [
NavigationDestination(
selectedIcon: Icon(Icons.table_rows),
icon: Icon(Icons.table_rows_outlined),
label: 'Schedule',
),
NavigationDestination(
selectedIcon: Icon(Icons.people),
icon: Icon(Icons.people_alt_outlined),
label: 'Teams',
),
NavigationDestination(
selectedIcon: Icon(Icons.analytics),
icon: Icon(Icons.analytics_outlined),
label: 'Analysis',
),
NavigationDestination(
selectedIcon: Icon(Icons.book),
icon: Icon(Icons.book_outlined),
label: 'Docs',
),
],
),
bottomNavigationBar: largeDevice
? null
: NavigationBar(
onDestinationSelected: (int index) {
setState(() {
_currentPageIndex = index;
});
},
selectedIndex: _currentPageIndex,
destinations: const [
NavigationDestination(
selectedIcon: Icon(Icons.calendar_today),
icon: Icon(Icons.calendar_today_outlined),
label: 'Schedule',
),
NavigationDestination(
selectedIcon: Icon(Icons.people),
icon: Icon(Icons.people_alt_outlined),
label: 'Teams',
),
NavigationDestination(
selectedIcon: Icon(Icons.analytics),
icon: Icon(Icons.analytics_outlined),
label: 'Analysis',
),
NavigationDestination(
selectedIcon: Icon(Icons.book),
icon: Icon(Icons.book_outlined),
label: 'Docs',
),
],
),
);
}
}
47 changes: 39 additions & 8 deletions app/lib/screens/documentation_page.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import 'dart:convert';
import 'dart:typed_data';

import 'package:app/helpers.dart';
import 'package:app/providers/data_provider.dart';
import 'package:app/providers/identity_provider.dart';
import 'package:app/screens/debug_field_position.dart';
import 'package:app/widgets/image_view.dart';
import 'package:app/widgets/markdown_wrapper.dart';
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
import 'package:snout_db/patch.dart';
import 'package:url_launcher/url_launcher_string.dart';

class DocumentationScreen extends StatefulWidget {
Expand All @@ -21,7 +25,7 @@ class _DocumentationScreenState extends State<DocumentationScreen> {

@override
Widget build(BuildContext context) {
final data = context.watch<DataProvider>().event.config;
final config = context.watch<DataProvider>().event.config;

final pitMap = context.watch<DataProvider>().event.pitmap;

Expand Down Expand Up @@ -59,13 +63,40 @@ class _DocumentationScreenState extends State<DocumentationScreen> {
)),
if (pitMap == null)
const ListTile(title: Text("No pit map has been added yet :(")),
ListTile(
title: const Text("Set Pit Map Image"),
trailing: const Icon(Icons.camera_alt),
onTap: () async {
final identity = context.read<IdentityProvider>().identity;
final dataProvider = context.read<DataProvider>();

String result;
//TAKE PHOTO
try {
final photo = await pickOrTakeImageDialog(context);
if (photo != null) {
Uint8List bytes = await photo.readAsBytes();
result = base64Encode(bytes);
Patch patch = Patch(
identity: identity,
time: DateTime.now(),
path: Patch.buildPath(['pitmap']),
value: result);
//Save the scouting results to the server!!
await dataProvider.submitPatch(patch);
}
} catch (e, s) {
Logger.root.severe("Error taking image from device", e, s);
}
},
),
const Divider(),
Padding(
padding: const EdgeInsets.only(left: 16, right: 16),
child: MarkdownText(
data: data.docs.isNotEmpty
? data.docs
: "# Welcome to the docs for ${data.name}\n**this is a temporary message that will be replaced once you set the docs property in the event config**\n\neverything that you collect should be defined in here, all 'docs' properties in the configuration support markdown"),
data: config.docs.isNotEmpty
? config.docs
: "# Welcome to the docs for ${config.name}\n**this is a temporary message that will be replaced once you set the docs property in the event config**\n\neverything that you collect should be defined in here, all 'docs' properties in the configuration support markdown"),
),
const Divider(),
ListTile(
Expand All @@ -82,7 +113,7 @@ class _DocumentationScreenState extends State<DocumentationScreen> {
child: Text("Pit Scouting",
style: Theme.of(context).textTheme.titleLarge),
),
for (final item in data.pitscouting) ...[
for (final item in config.pitscouting) ...[
Padding(
padding: const EdgeInsets.only(left: 16, top: 16),
child: Text(item.label,
Expand Down Expand Up @@ -117,7 +148,7 @@ class _DocumentationScreenState extends State<DocumentationScreen> {
child: Text("Match Events",
style: Theme.of(context).textTheme.titleLarge),
),
for (final item in data.matchscouting.events) ...[
for (final item in config.matchscouting.events) ...[
Padding(
padding: const EdgeInsets.only(left: 16, top: 16),
child: Text(item.label,
Expand Down Expand Up @@ -146,7 +177,7 @@ class _DocumentationScreenState extends State<DocumentationScreen> {
child: Text("Match Survey",
style: Theme.of(context).textTheme.titleLarge),
),
for (final item in data.matchscouting.survey) ...[
for (final item in config.matchscouting.survey) ...[
Padding(
padding: const EdgeInsets.only(left: 16, top: 16),
child: Text(item.label,
Expand Down Expand Up @@ -181,7 +212,7 @@ class _DocumentationScreenState extends State<DocumentationScreen> {
child:
Text("Processes", style: Theme.of(context).textTheme.titleLarge),
),
for (final item in data.matchscouting.processes) ...[
for (final item in config.matchscouting.processes) ...[
Padding(
padding: const EdgeInsets.only(left: 16, top: 16),
child: Text(item.label,
Expand Down
4 changes: 2 additions & 2 deletions app/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,10 @@ packages:
dependency: "direct main"
description:
name: fl_chart
sha256: c1e26c7e48496be85104c16c040950b0436674cdf0737f3f6e95511b2529b592
sha256: "6b9eb2b3017241d05c482c01f668dd05cc909ec9a0114fdd49acd958ff2432fa"
url: "https://pub.dev"
source: hosted
version: "0.63.0"
version: "0.64.0"
flutter:
dependency: "direct main"
description: flutter
Expand Down
2 changes: 1 addition & 1 deletion app/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ dependencies:
url_launcher: ^6.1.7
download: ^1.0.0
csv: ^5.0.1
fl_chart: ^0.63.0
fl_chart: ^0.64.0
flutter_markdown: ^0.6.17+1
# Potential alternate charting package: https://pub.dev/packages/community_charts_flutter

Expand Down
3 changes: 0 additions & 3 deletions server/lib/edit_lock.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ class EditLock {

//Returns true if the lock is active.
bool get (String key) {
print(locks);
final value = locks[key];
if(value != null) {
if(value.add(const Duration(minutes: 15)).isAfter(DateTime.now())) {
Expand All @@ -20,11 +19,9 @@ class EditLock {

void set (String key) {
locks[key] = DateTime.now();
print(locks);
}

void clear (String key) {
locks.remove(key);
print(locks);
}
}
Loading

0 comments on commit a16abdf

Please sign in to comment.