Change responsive design

This commit is contained in:
Jakob Kordež 2022-08-12 18:29:51 +02:00
parent 8b0180f091
commit 3fe0f46c75
7 changed files with 251 additions and 258 deletions

View File

@ -1,29 +1,7 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
avoid_print: false # Uncomment to disable the `avoid_print` rule
prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
avoid_print: false
prefer_single_quotes: true
prefer_relative_imports: true

View File

@ -1,228 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../cubit/questions_cubit.dart';
import '../models/category.dart';
import '../quiz/cubit/quiz_cubit.dart';
import 'cubit/generator_cubit.dart';
class PracticeTab extends StatelessWidget {
const PracticeTab({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Vaja',
style: Theme.of(context).textTheme.headlineSmall,
),
const SizedBox(height: 15),
const Text(
'Izberi pogročje in vpiši število vprašanj, ki jih želiš generirati. '
'Če želiš generirati vprašanja iz vseh področij, pusti polje za področje prazno.'),
const SizedBox(height: 20),
LayoutBuilder(
builder: (context, constraints) {
final mxW = constraints.maxWidth - 80;
return Wrap(
alignment: WrapAlignment.center,
spacing: 10,
crossAxisAlignment: WrapCrossAlignment.end,
children: [
Container(
width: mxW * 2 / 3,
constraints: const BoxConstraints(minWidth: 500),
child: _CategoryInput(),
),
Container(
width: mxW / 3,
constraints: const BoxConstraints(minWidth: 100),
child: _PracticeQuestionNumberInput(),
),
],
);
},
),
const SizedBox(height: 20),
Container(
alignment: Alignment.bottomRight,
child: ElevatedButton(
onPressed: () {
final generatorState = context.read<GeneratorCubit>().state;
final questionsState =
context.read<QuestionsCubit>().state as QuestionsLoaded;
Navigator.pushNamed(context, '/quiz',
arguments: QuizState(
title: generatorState.category == null
? 'Vaja - Vse kategorije'
: 'Vaja - ${generatorState.category!.title}',
questions:
questionsState.getRandom(generatorState.category?.id),
count: generatorState.practiceQuestionCount,
revealInstantly: true,
));
},
child: const Text('Začni'),
),
),
],
);
}
class _CategoryInput extends StatelessWidget {
@override
Widget build(BuildContext context) =>
BlocBuilder<QuestionsCubit, QuestionsState>(
builder: (context, qstate) =>
BlocBuilder<GeneratorCubit, GeneratorState>(
builder: (context, gstate) {
qstate as QuestionsLoaded;
return DropdownButtonFormField<Category>(
isExpanded: true,
value: gstate.category,
decoration: InputDecoration(
isDense: true,
enabled: gstate.singleCategory,
labelText: 'Izberi področje',
suffixIcon: gstate.category == null
? null
: IconButton(
splashRadius: 18,
icon: const Icon(Icons.clear),
onPressed: () => context
.read<GeneratorCubit>()
.setSingleCategory(false),
),
),
items: qstate.categories
.map((e) => DropdownMenuItem(
value: e,
child: Text(
e.title,
overflow: TextOverflow.ellipsis,
),
))
.toList(),
onChanged: (value) {
if (value == null) return;
context.read<GeneratorCubit>().setCategory(value);
},
);
},
),
);
}
class _PracticeQuestionNumberInput extends StatelessWidget {
@override
Widget build(BuildContext context) =>
BlocBuilder<GeneratorCubit, GeneratorState>(
buildWhen: (previous, current) =>
previous.practiceQuestionCount != current.practiceQuestionCount,
builder: (context, state) => TextFormField(
initialValue: '${state.practiceQuestionCount}',
decoration: const InputDecoration(
labelText: 'Število vprašanj',
),
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
keyboardType: TextInputType.number,
onChanged: context.read<GeneratorCubit>().setPracticeQuestionCount,
),
);
}
class _TestQuestionNumberInput extends StatelessWidget {
@override
Widget build(BuildContext context) =>
BlocBuilder<GeneratorCubit, GeneratorState>(
buildWhen: (previous, current) =>
previous.testQuestionCount != current.testQuestionCount,
builder: (context, state) => TextFormField(
initialValue: '${state.testQuestionCount}',
decoration: const InputDecoration(
labelText: 'Število vprašanj',
),
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
keyboardType: TextInputType.number,
onChanged: context.read<GeneratorCubit>().setTestQuestionCount,
),
);
}
class TestTab extends StatelessWidget {
const TestTab({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Preizkus uspeha',
style: Theme.of(context).textTheme.headlineSmall,
),
const SizedBox(height: 15),
const Text(
'Kandidati za radioamaterja razreda A opravljajo izpit, ki je '
'sestavljen iz 60 različnih vprašanj. Vsako vprašanje ima 3 možne odgovore, od katerih je '
'samo en pravilen. Kandidat ima na voljo 90 minut za reševanje izpitne pole. Kandidat mora '
'pravilno odgovoriti vsaj na 36 vprašanj (60%).'),
const SizedBox(height: 20),
const Text(
'Preizkus uspeha NE bo vseboval vprašanj s področja "Risanje"!'),
const SizedBox(height: 20),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(child: _TestQuestionNumberInput()),
const SizedBox(width: 10),
Expanded(child: _DurationInput()),
],
),
const SizedBox(height: 20),
Container(
alignment: Alignment.bottomRight,
child: ElevatedButton(
onPressed: () {
final generatorState = context.read<GeneratorCubit>().state;
final questionsState =
context.read<QuestionsCubit>().state as QuestionsLoaded;
Navigator.pushNamed(context, '/quiz',
arguments: QuizState(
title: 'Preizkus uspeha',
questions: questionsState
.getRandom(null, true)
.take(generatorState.testQuestionCount)
.toList(),
count: generatorState.testQuestionCount,
duration: generatorState.timerDuration,
revealInstantly: false,
));
},
child: const Text('Naprej'),
),
),
],
);
}
class _DurationInput extends StatelessWidget {
@override
Widget build(BuildContext context) =>
BlocBuilder<GeneratorCubit, GeneratorState>(
buildWhen: (previous, current) =>
previous.timerDuration != current.timerDuration,
builder: (context, state) => TextFormField(
initialValue: '${state.timerDuration.inMinutes}',
decoration: const InputDecoration(
suffixText: 'min',
labelText: 'Čas za reševanje',
),
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
keyboardType: TextInputType.number,
onChanged: context.read<GeneratorCubit>().setDuration,
),
);
}

View File

@ -0,0 +1,141 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../cubit/questions_cubit.dart';
import '../models/category.dart';
import '../quiz/cubit/quiz_cubit.dart';
import 'cubit/generator_cubit.dart';
class PracticeTab extends StatelessWidget {
const PracticeTab({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Vaja',
style: Theme.of(context).textTheme.headlineSmall,
),
const SizedBox(height: 15),
const Text(
'Izberi pogročje in vpiši število vprašanj, ki jih želiš generirati. '
'Če želiš generirati vprašanja iz vseh področij, pusti polje za področje prazno.'),
const SizedBox(height: 20),
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 600) {
return Row(
children: [
Expanded(
flex: 2,
child: _CategoryInput(),
),
const SizedBox(width: 10),
Expanded(
flex: 1,
child: _QuestionNumberInput(),
),
],
);
}
return Column(
mainAxisSize: MainAxisSize.min,
children: [
_CategoryInput(),
const SizedBox(height: 15),
_QuestionNumberInput(),
],
);
},
),
const SizedBox(height: 20),
Container(
alignment: Alignment.bottomRight,
child: ElevatedButton(
onPressed: () {
final generatorState = context.read<GeneratorCubit>().state;
final questionsState =
context.read<QuestionsCubit>().state as QuestionsLoaded;
Navigator.pushNamed(context, '/quiz',
arguments: QuizState(
title: generatorState.category == null
? 'Vaja - Vse kategorije'
: 'Vaja - ${generatorState.category!.title}',
questions:
questionsState.getRandom(generatorState.category?.id),
count: generatorState.practiceQuestionCount,
revealInstantly: true,
));
},
child: const Text('Začni'),
),
),
],
);
}
class _CategoryInput extends StatelessWidget {
@override
Widget build(BuildContext context) =>
BlocBuilder<QuestionsCubit, QuestionsState>(
builder: (context, qstate) =>
BlocBuilder<GeneratorCubit, GeneratorState>(
builder: (context, gstate) {
qstate as QuestionsLoaded;
return DropdownButtonFormField<Category>(
isExpanded: true,
value: gstate.category,
decoration: InputDecoration(
isDense: true,
enabled: gstate.singleCategory,
labelText: 'Izberi področje',
suffixIcon: gstate.category == null
? null
: IconButton(
splashRadius: 18,
icon: const Icon(Icons.clear),
onPressed: () => context
.read<GeneratorCubit>()
.setSingleCategory(false),
),
),
items: qstate.categories
.map((e) => DropdownMenuItem(
value: e,
child: Text(
e.title,
overflow: TextOverflow.ellipsis,
),
))
.toList(),
onChanged: (value) {
if (value == null) return;
context.read<GeneratorCubit>().setCategory(value);
},
);
},
),
);
}
class _QuestionNumberInput extends StatelessWidget {
@override
Widget build(BuildContext context) =>
BlocBuilder<GeneratorCubit, GeneratorState>(
buildWhen: (previous, current) =>
previous.practiceQuestionCount != current.practiceQuestionCount,
builder: (context, state) => TextFormField(
initialValue: '${state.practiceQuestionCount}',
decoration: const InputDecoration(
labelText: 'Število vprašanj',
),
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
keyboardType: TextInputType.number,
onChanged: context.read<GeneratorCubit>().setPracticeQuestionCount,
),
);
}

View File

@ -0,0 +1,100 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../cubit/questions_cubit.dart';
import '../quiz/cubit/quiz_cubit.dart';
import 'cubit/generator_cubit.dart';
class TestTab extends StatelessWidget {
const TestTab({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Preizkus uspeha',
style: Theme.of(context).textTheme.headlineSmall,
),
const SizedBox(height: 15),
const Text(
'Kandidati za radioamaterja razreda A opravljajo izpit, ki je '
'sestavljen iz 60 različnih vprašanj. Vsako vprašanje ima 3 možne odgovore, od katerih je '
'samo en pravilen. Kandidat ima na voljo 90 minut za reševanje izpitne pole. Kandidat mora '
'pravilno odgovoriti vsaj na 36 vprašanj (60%).'),
const SizedBox(height: 20),
const Text(
'Preizkus uspeha NE bo vseboval vprašanj s področja "Risanje"!'),
const SizedBox(height: 20),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(child: _TestQuestionNumberInput()),
const SizedBox(width: 10),
Expanded(child: _DurationInput()),
],
),
const SizedBox(height: 20),
Container(
alignment: Alignment.bottomRight,
child: ElevatedButton(
onPressed: () {
final generatorState = context.read<GeneratorCubit>().state;
final questionsState =
context.read<QuestionsCubit>().state as QuestionsLoaded;
Navigator.pushNamed(context, '/quiz',
arguments: QuizState(
title: 'Preizkus uspeha',
questions: questionsState
.getRandom(null, true)
.take(generatorState.testQuestionCount)
.toList(),
count: generatorState.testQuestionCount,
duration: generatorState.timerDuration,
revealInstantly: false,
));
},
child: const Text('Naprej'),
),
),
],
);
}
class _TestQuestionNumberInput extends StatelessWidget {
@override
Widget build(BuildContext context) =>
BlocBuilder<GeneratorCubit, GeneratorState>(
buildWhen: (previous, current) =>
previous.testQuestionCount != current.testQuestionCount,
builder: (context, state) => TextFormField(
initialValue: '${state.testQuestionCount}',
decoration: const InputDecoration(
labelText: 'Število vprašanj',
),
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
keyboardType: TextInputType.number,
onChanged: context.read<GeneratorCubit>().setTestQuestionCount,
),
);
}
class _DurationInput extends StatelessWidget {
@override
Widget build(BuildContext context) =>
BlocBuilder<GeneratorCubit, GeneratorState>(
buildWhen: (previous, current) =>
previous.timerDuration != current.timerDuration,
builder: (context, state) => TextFormField(
initialValue: '${state.timerDuration.inMinutes}',
decoration: const InputDecoration(
suffixText: 'min',
labelText: 'Čas za reševanje',
),
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
keyboardType: TextInputType.number,
onChanged: context.read<GeneratorCubit>().setDuration,
),
);
}

View File

@ -1,10 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:s5_practice/src/cubit/questions_cubit.dart';
import 'package:s5_practice/src/generator/generator_form.dart';
import 'components/sized_card.dart';
import 'cubit/questions_cubit.dart';
import 'generator/cubit/generator_cubit.dart';
import 'generator/practice_tab.dart';
import 'generator/test_tab.dart';
class HomeScreen extends StatelessWidget {
static const _tabs = [

View File

@ -2,7 +2,8 @@ import 'dart:math';
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:s5_practice/src/models/question.dart';
import '../../models/question.dart';
part 'quiz_state.dart';

View File

@ -2,10 +2,10 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:s5_practice/src/components/sized_card.dart';
import 'package:s5_practice/src/quiz/cubit/quiz_cubit.dart';
import 'package:timer_builder/timer_builder.dart';
import '../components/sized_card.dart';
import 'cubit/quiz_cubit.dart';
import 'question_card.dart';
class QuizScreen extends StatefulWidget {