Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 32-improve-app-metadata
  • master
  • Release_0.0.10_10
  • Release_0.0.11_11
  • Release_0.0.12_12
  • Release_0.0.13_13
  • Release_0.0.14_14
  • Release_0.0.15_15
  • Release_0.0.16_16
  • Release_0.0.17_17
  • Release_0.0.18_18
  • Release_0.0.19_19
  • Release_0.0.20_20
  • Release_0.0.21_21
  • Release_0.0.22_22
  • Release_0.0.23_23
  • Release_0.0.24_24
  • Release_0.0.25_25
  • Release_0.0.26_26
  • Release_0.0.2_2
  • Release_0.0.3_3
  • Release_0.0.4_4
  • Release_0.0.5_5
  • Release_0.0.6_6
  • Release_0.0.7_7
  • Release_0.0.8_8
  • Release_0.0.9_9
  • Release_0.1.0_27
  • Release_0.1.1_28
  • Release_0.1.2_29
  • Release_0.2.0_30
  • Release_0.2.1_31
  • Release_0.3.0_32
  • Release_0.3.1_33
  • Release_0.4.0_34
  • Release_0.4.1_35
  • Release_0.4.2_36
  • Release_0.5.0_37
  • Release_0.6.0_38
  • Release_0.7.0_39
  • Release_0.8.0_40
  • Release_0.8.1_41
  • Release_0.8.2_42
  • Release_0.9.0_43
  • Release_0.9.1_44
45 results

Target

Select target project
  • android/org.benoitharrault.sortgame
1 result
Select Git revision
  • 32-improve-app-metadata
  • master
  • Release_0.0.10_10
  • Release_0.0.11_11
  • Release_0.0.12_12
  • Release_0.0.13_13
  • Release_0.0.14_14
  • Release_0.0.15_15
  • Release_0.0.16_16
  • Release_0.0.17_17
  • Release_0.0.18_18
  • Release_0.0.19_19
  • Release_0.0.20_20
  • Release_0.0.21_21
  • Release_0.0.22_22
  • Release_0.0.23_23
  • Release_0.0.24_24
  • Release_0.0.25_25
  • Release_0.0.26_26
  • Release_0.0.2_2
  • Release_0.0.3_3
  • Release_0.0.4_4
  • Release_0.0.5_5
  • Release_0.0.6_6
  • Release_0.0.7_7
  • Release_0.0.8_8
  • Release_0.0.9_9
  • Release_0.1.0_27
  • Release_0.1.1_28
  • Release_0.1.2_29
  • Release_0.2.0_30
  • Release_0.2.1_31
  • Release_0.3.0_32
  • Release_0.3.1_33
  • Release_0.4.0_34
  • Release_0.4.1_35
  • Release_0.4.2_36
  • Release_0.5.0_37
  • Release_0.6.0_38
  • Release_0.7.0_39
  • Release_0.8.0_40
  • Release_0.8.1_41
  • Release_0.8.2_42
  • Release_0.9.0_43
  • Release_0.9.1_44
45 results
Show changes
Showing
with 1031 additions and 78 deletions
class Item {
final String key;
final String text;
const Item({
required this.key,
required this.text,
});
Map<String, dynamic> toJson() {
return {
'key': key,
'text': text,
};
}
@override
String toString() {
return toJson().toString();
}
}
import 'package:sortgame/data/fetch_data_helper.dart';
import 'package:sortgame/models/data/game_item.dart';
import 'package:sortgame/models/settings_game.dart';
import 'package:sortgame/models/settings_global.dart';
import 'package:sortgame/utils/tools.dart';
class Game {
final List<GameItem> items;
final GameSettings gameSettings;
final GlobalSettings globalSettings;
bool isRunning = false;
bool isFinished = false;
int position = 1;
int score = 0;
Game({
required this.items,
required this.gameSettings,
required this.globalSettings,
this.isRunning = false,
this.isFinished = false,
this.position = 1,
this.score = 0,
});
factory Game.createNull() {
return Game(
items: [],
gameSettings: GameSettings.createDefault(),
globalSettings: GlobalSettings.createDefault(),
);
}
factory Game.createNew({
GameSettings? gameSettings,
GlobalSettings? globalSettings,
}) {
GameSettings newGameSettings = gameSettings ?? GameSettings.createDefault();
GlobalSettings newGlobalSettings = globalSettings ?? GlobalSettings.createDefault();
List<GameItem> items = FetchDataHelper().getItems(newGameSettings);
return Game(
items: items,
gameSettings: newGameSettings,
globalSettings: newGlobalSettings,
isRunning: true,
);
}
void increaseScore(int? count) {
score += (count ?? 0);
}
void increasePosition() {
position += 1;
}
void updateGameIsRunning(bool gameIsRunning) {
isRunning = gameIsRunning;
}
void updateGameIsFinished(bool gameIsFinished) {
isFinished = gameIsFinished;
}
GameItem getCurrentGameItem() {
return items[position - 1];
}
void dump() {
printlog('');
printlog('## Current game dump:');
printlog('');
gameSettings.dump();
globalSettings.dump();
printlog('');
items.toString();
printlog('');
printlog('Game: ');
printlog(' isRunning: $isRunning');
printlog(' isFinished: $isFinished');
printlog(' position: $position');
printlog(' score: $score');
printlog('');
}
@override
String toString() {
return '$Game(${toJson()})';
}
Map<String, dynamic>? toJson() {
return <String, dynamic>{
'items': items.toString(),
'gameSettings': gameSettings.toJson(),
'globalSettings': globalSettings.toJson(),
'isRunning': isRunning,
'isFinished': isFinished,
'position': position,
'score': score,
};
}
}
import 'package:sortgame/config/default_game_settings.dart';
import 'package:sortgame/utils/tools.dart';
class GameSettings {
final int itemsCount;
final int theme;
GameSettings({
required this.itemsCount,
required this.theme,
});
static int getItemsCountValueFromUnsafe(int itemsCount) {
if (DefaultGameSettings.allowedItemsCountValues.contains(itemsCount)) {
return itemsCount;
}
return DefaultGameSettings.defaultItemsCountValue;
}
static int getThemeValueFromUnsafe(int theme) {
if (DefaultGameSettings.getAvailableValues('theme').contains(theme)) {
return theme;
}
return DefaultGameSettings.defaultThemeValue;
}
factory GameSettings.createDefault() {
return GameSettings(
itemsCount: DefaultGameSettings.defaultItemsCountValue,
theme: DefaultGameSettings.defaultThemeValue,
);
}
void dump() {
printlog('Settings: ');
printlog(' itemsCount: $itemsCount');
printlog(' theme: $theme');
}
@override
String toString() {
return '$GameSettings(${toJson()})';
}
Map<String, dynamic>? toJson() {
return <String, dynamic>{
'itemsCount': itemsCount,
'theme': theme,
};
}
}
import 'package:sortgame/utils/tools.dart';
class GlobalSettings {
GlobalSettings();
factory GlobalSettings.createDefault() {
return GlobalSettings();
}
void dump() {
printlog('Settings: ');
}
@override
String toString() {
return '$GlobalSettings(${toJson()})';
}
Map<String, dynamic>? toJson() {
return <String, dynamic>{};
}
}
import 'package:flutter/foundation.dart';
class Data extends ChangeNotifier {
bool _searchingImage = false;
String _image = '';
bool get searchingImage => _searchingImage;
set searchingImage(bool value) {
_searchingImage = value;
notifyListeners();
}
String get image => _image;
set updateImage(String value) {
_image = value;
notifyListeners();
}
void resetGame() {
_image = '';
notifyListeners();
}
}
import 'package:flutter/material.dart';
class Home extends StatelessWidget {
static const String id = 'home';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Sorting game'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.all(4),
padding: EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(4),
border: Border.all(
color: Colors.green,
width: 4,
),
),
child: TextButton(
child: Text(
'🎲',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 50,
fontWeight: FontWeight.w600,
color: Colors.black,
),
),
onPressed: () => print('X'),
),
),
],
),
),
],
),
),
);
}
}
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:sortgame/config/default_game_settings.dart';
import 'package:sortgame/data/fetch_data_helper.dart';
import 'package:sortgame/models/data/game_theme.dart';
import 'package:sortgame/models/settings_game.dart';
import 'package:sortgame/models/settings_global.dart';
import 'package:sortgame/utils/tools.dart';
class ParameterPainter extends CustomPainter {
const ParameterPainter({
required this.code,
required this.value,
required this.isSelected,
required this.gameSettings,
required this.globalSettings,
});
final String code;
final int value;
final bool isSelected;
final GameSettings gameSettings;
final GlobalSettings globalSettings;
@override
void paint(Canvas canvas, Size size) {
// force square
final double canvasSize = min(size.width, size.height);
const Color borderColorEnabled = Colors.blue;
const Color borderColorDisabled = Colors.white;
// "enabled/disabled" border
final paint = Paint();
paint.style = PaintingStyle.stroke;
paint.color = isSelected ? borderColorEnabled : borderColorDisabled;
paint.strokeJoin = StrokeJoin.round;
paint.strokeWidth = 20 / 100 * canvasSize;
canvas.drawRect(
Rect.fromPoints(const Offset(0, 0), Offset(canvasSize, canvasSize)), paint);
// content
switch (code) {
case 'itemsCount':
paintItemsCountParameterItem(value, canvas, canvasSize);
break;
case 'theme':
paintThemeParameterItem(value, canvas, canvasSize);
break;
default:
printlog('Unknown parameter: $code/$value');
paintUnknownParameterItem(value, canvas, canvasSize);
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
// "unknown" parameter -> simple bock with text
void paintUnknownParameterItem(
final int value,
final Canvas canvas,
final double size,
) {
final paint = Paint();
paint.strokeJoin = StrokeJoin.round;
paint.strokeWidth = 3 / 100 * size;
paint.color = Colors.grey;
paint.style = PaintingStyle.fill;
canvas.drawRect(Rect.fromPoints(const Offset(0, 0), Offset(size, size)), paint);
final textSpan = TextSpan(
text: '?\n$value',
style: const TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold,
),
);
final textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.ltr,
);
textPainter.layout();
textPainter.paint(
canvas,
Offset(
(size - textPainter.width) * 0.5,
(size - textPainter.height) * 0.5,
),
);
}
void paintItemsCountParameterItem(
final int value,
final Canvas canvas,
final double size,
) {
Color backgroundColor = Colors.grey;
switch (value) {
case DefaultGameSettings.itemsCountValueLow:
backgroundColor = Colors.green;
break;
case DefaultGameSettings.itemsCountValueMedium:
backgroundColor = Colors.orange;
break;
case DefaultGameSettings.itemsCountValueHigh:
backgroundColor = Colors.red;
break;
case DefaultGameSettings.itemsCountValueVeryHigh:
backgroundColor = Colors.purple;
break;
default:
printlog('Wrong value for itemsCount parameter value: $value');
}
final paint = Paint();
paint.strokeJoin = StrokeJoin.round;
paint.strokeWidth = 3 / 100 * size;
// Colored background
paint.color = backgroundColor;
paint.style = PaintingStyle.fill;
canvas.drawRect(Rect.fromPoints(const Offset(0, 0), Offset(size, size)), paint);
// centered text value
final textSpan = TextSpan(
text: value.toString(),
style: TextStyle(
color: Colors.black,
fontSize: size / 4,
fontWeight: FontWeight.bold,
),
);
final textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.ltr,
);
textPainter.layout();
textPainter.paint(
canvas,
Offset(
(size - textPainter.width) * 0.5,
(size - textPainter.height) * 0.5,
),
);
}
void paintThemeParameterItem(
final int value,
final Canvas canvas,
final double size,
) {
final GameTheme theme = FetchDataHelper().getTheme(value);
final Color backgroundColor =
Color((theme.code.hashCode * 0xFFFFFF).toInt()).withOpacity(1.0);
final paint = Paint();
paint.strokeJoin = StrokeJoin.round;
paint.strokeWidth = 3 / 100 * size;
// Colored background
paint.color = backgroundColor;
paint.style = PaintingStyle.fill;
canvas.drawRect(Rect.fromPoints(const Offset(0, 0), Offset(size, size)), paint);
// centered text value
final textSpan = TextSpan(
text: theme.code,
style: TextStyle(
color: Colors.black,
fontSize: size / 4,
fontWeight: FontWeight.bold,
),
);
final textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.ltr,
);
textPainter.layout();
textPainter.paint(
canvas,
Offset(
(size - textPainter.width) * 0.5,
(size - textPainter.height) * 0.5,
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sortgame/cubit/game_cubit.dart';
import 'package:sortgame/models/game.dart';
import 'package:sortgame/ui/widgets/game_bottom_buttons.dart';
import 'package:sortgame/ui/widgets/game_question.dart';
import 'package:sortgame/ui/widgets/game_top_indicator.dart';
class ScreenGame extends StatelessWidget {
const ScreenGame({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<GameCubit, GameState>(
builder: (BuildContext context, GameState gameState) {
final Game currentGame = gameState.currentGame;
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 8),
const GameTopIndicatorWidget(),
const SizedBox(height: 8),
Expanded(
child: !currentGame.isFinished
? const GameQuestionWidget()
: const SizedBox(height: 8),
),
!currentGame.isFinished
? const SizedBox(height: 8)
: const GameBottomButtonsWidget(),
],
);
},
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sortgame/config/default_game_settings.dart';
import 'package:sortgame/config/default_global_settings.dart';
import 'package:sortgame/cubit/game_cubit.dart';
import 'package:sortgame/cubit/settings_game_cubit.dart';
import 'package:sortgame/cubit/settings_global_cubit.dart';
import 'package:sortgame/ui/painters/parameter_painter.dart';
class ScreenParameters extends StatelessWidget {
const ScreenParameters({super.key});
final double separatorHeight = 8.0;
@override
Widget build(BuildContext context) {
final List<Widget> lines = [];
// Game settings
for (String code in DefaultGameSettings.availableParameters) {
lines.add(Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: buildParametersLine(
code: code,
isGlobal: false,
),
));
lines.add(SizedBox(height: separatorHeight));
}
lines.add(SizedBox(height: separatorHeight));
lines.add(Expanded(child: buildStartNewGameButton()));
lines.add(SizedBox(height: separatorHeight));
// Global settings
for (String code in DefaultGlobalSettings.availableParameters) {
lines.add(Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: buildParametersLine(
code: code,
isGlobal: true,
),
));
lines.add(SizedBox(height: separatorHeight));
}
return Column(
children: lines,
);
}
List<Widget> buildParametersLine({
required String code,
required bool isGlobal,
}) {
final List<Widget> parameterButtons = [];
final List<int> availableValues = isGlobal
? DefaultGlobalSettings.getAvailableValues(code)
: DefaultGameSettings.getAvailableValues(code);
for (int value in availableValues) {
final Widget parameterButton = BlocBuilder<GameSettingsCubit, GameSettingsState>(
builder: (BuildContext context, GameSettingsState gameSettingsState) {
return BlocBuilder<GlobalSettingsCubit, GlobalSettingsState>(
builder: (BuildContext context, GlobalSettingsState globalSettingsState) {
final GameSettingsCubit gameSettingsCubit =
BlocProvider.of<GameSettingsCubit>(context);
final GlobalSettingsCubit globalSettingsCubit =
BlocProvider.of<GlobalSettingsCubit>(context);
final int currentValue = isGlobal
? globalSettingsCubit.getParameterValue(code)
: gameSettingsCubit.getParameterValue(code);
final bool isActive = (value == currentValue);
final double displayWidth = MediaQuery.of(context).size.width;
final double itemWidth = displayWidth / availableValues.length - 25;
return TextButton(
child: Container(
margin: const EdgeInsets.all(0),
padding: const EdgeInsets.all(0),
child: CustomPaint(
size: Size(itemWidth, itemWidth),
willChange: false,
painter: ParameterPainter(
code: code,
value: value,
isSelected: isActive,
gameSettings: gameSettingsState.settings,
globalSettings: globalSettingsState.settings,
),
isComplex: true,
),
),
onPressed: () => isGlobal
? globalSettingsCubit.setParameterValue(code, value)
: gameSettingsCubit.setParameterValue(code, value),
);
},
);
},
);
parameterButtons.add(parameterButton);
}
return parameterButtons;
}
Image buildImageWidget(String imageAssetCode) {
return Image(
image: AssetImage('assets/icons/$imageAssetCode.png'),
fit: BoxFit.fill,
);
}
Container buildImageContainerWidget(String imageAssetCode) {
return Container(
child: buildImageWidget(imageAssetCode),
);
}
Column buildDecorationImageWidget() {
return Column(
children: [
TextButton(
child: buildImageContainerWidget('placeholder'),
onPressed: () {},
),
],
);
}
Widget buildStartNewGameButton() {
return BlocBuilder<GameSettingsCubit, GameSettingsState>(
builder: (BuildContext context, GameSettingsState gameSettingsState) {
return BlocBuilder<GlobalSettingsCubit, GlobalSettingsState>(
builder: (BuildContext context, GlobalSettingsState globalSettingsState) {
final GameCubit gameCubit = BlocProvider.of<GameCubit>(context);
return TextButton(
child: buildImageContainerWidget('button_start'),
onPressed: () => gameCubit.startNewGame(
gameSettings: gameSettingsState.settings,
globalSettings: globalSettingsState.settings,
),
);
},
);
},
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sortgame/cubit/game_cubit.dart';
import 'package:sortgame/ui/screens/screen_game.dart';
import 'package:sortgame/ui/screens/screen_parameters.dart';
import 'package:sortgame/ui/widgets/global_app_bar.dart';
class SkeletonScreen extends StatelessWidget {
const SkeletonScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const GlobalAppBar(),
extendBodyBehindAppBar: false,
body: Material(
color: Theme.of(context).colorScheme.background,
child: BlocBuilder<GameCubit, GameState>(
builder: (BuildContext context, GameState gameState) {
return gameState.currentGame.isRunning
? const ScreenGame()
: const ScreenParameters();
},
),
),
backgroundColor: Theme.of(context).colorScheme.background,
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sortgame/cubit/game_cubit.dart';
class GameBottomButtonsWidget extends StatelessWidget {
const GameBottomButtonsWidget({super.key});
@override
Widget build(BuildContext context) {
const String decorationImageAssetName = 'assets/icons/placeholder.png';
const Widget decorationWidget = TextButton(
onPressed: null,
child: Image(
image: AssetImage(decorationImageAssetName),
fit: BoxFit.fill,
),
);
return Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: [
TableRow(
children: [
const Column(
children: [decorationWidget],
),
Column(
children: [
TextButton(
child: const Image(
image: AssetImage('assets/icons/button_back.png'),
fit: BoxFit.fill,
),
onPressed: () {
final GameCubit gameCubit = BlocProvider.of<GameCubit>(context);
gameCubit.quitGame();
},
)
],
),
const Column(
children: [decorationWidget],
),
],
),
],
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sortgame/cubit/game_cubit.dart';
import 'package:sortgame/models/data/game_item.dart';
import 'package:sortgame/models/game.dart';
import 'package:sortgame/ui/widgets/games/buttons_yes_no.dart';
import 'package:sortgame/ui/widgets/helpers/outlined_text_widget.dart';
class GameQuestionWidget extends StatelessWidget {
const GameQuestionWidget({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<GameCubit, GameState>(
builder: (BuildContext context, GameState gameState) {
final Game currentGame = gameState.currentGame;
final GameItem currentGameItem = currentGame.getCurrentGameItem();
return Column(
children: [
OutlinedText(
text: currentGameItem.item.text,
fontSize: 50,
textColor: Theme.of(context).colorScheme.onSurface,
),
Container(
padding: const EdgeInsets.all(10),
margin: const EdgeInsets.all(20),
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context).colorScheme.surface,
width: 8,
),
borderRadius: const BorderRadius.all(Radius.circular(20)),
color: Theme.of(context).colorScheme.inversePrimary,
),
child: GameButtonsYesNo(gameItem: currentGameItem),
),
],
);
},
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sortgame/cubit/game_cubit.dart';
import 'package:sortgame/models/game.dart';
import 'package:sortgame/ui/widgets/indicators/indicator_position.dart';
import 'package:sortgame/ui/widgets/indicators/indicator_score.dart';
class GameTopIndicatorWidget extends StatelessWidget {
const GameTopIndicatorWidget({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<GameCubit, GameState>(
builder: (BuildContext context, GameState gameState) {
final Game currentGame = gameState.currentGame;
return Column(
children: [
PositionIndicator(game: currentGame),
ScoreIndicator(game: currentGame),
],
);
},
);
}
}
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:unicons/unicons.dart';
import 'package:sortgame/cubit/game_cubit.dart';
import 'package:sortgame/models/data/category.dart';
import 'package:sortgame/models/data/game_item.dart';
class GameButtonsYesNo extends StatelessWidget {
const GameButtonsYesNo({super.key, required this.gameItem});
final GameItem gameItem;
@override
Widget build(BuildContext context) {
final GameCubit gameCubit = BlocProvider.of<GameCubit>(context);
final bool pickInIsCategory = Random().nextBool();
final List<Category> categories =
pickInIsCategory ? gameItem.isCategory : gameItem.isNotCategory;
categories.shuffle();
final Category category = categories.first;
return Column(
children: [
Text(
category.text,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontSize: 40,
fontWeight: FontWeight.bold,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
IconButton(
color: Theme.of(context).colorScheme.onSurface,
iconSize: 80,
onPressed: () {
if (pickInIsCategory) {
gameCubit.increaseScore(1);
}
gameCubit.increasePosition();
},
icon: const Icon(UniconsLine.thumbs_up),
),
Text(
category.emoji,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontSize: 40,
fontWeight: FontWeight.bold,
),
),
IconButton(
color: Theme.of(context).colorScheme.onSurface,
iconSize: 80,
onPressed: () {
if (!pickInIsCategory) {
gameCubit.increaseScore(1);
}
gameCubit.increasePosition();
},
icon: const Icon(UniconsLine.thumbs_down),
),
],
)
],
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sortgame/cubit/game_cubit.dart';
import 'package:sortgame/models/game.dart';
import 'package:sortgame/ui/widgets/helpers/app_titles.dart';
class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget {
const GlobalAppBar({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<GameCubit, GameState>(
builder: (BuildContext context, GameState gameState) {
final Game currentGame = gameState.currentGame;
final List<Widget> menuActions = [];
if (currentGame.isRunning) {
menuActions.add(TextButton(
child: const Image(
image: AssetImage('assets/icons/button_back.png'),
fit: BoxFit.fill,
),
onPressed: () {},
onLongPress: () {
final GameCubit gameCubit = BlocProvider.of<GameCubit>(context);
gameCubit.quitGame();
},
));
}
return AppBar(
title: const AppTitle(text: 'app_name'),
actions: menuActions,
);
},
);
}
@override
Size get preferredSize => const Size.fromHeight(50);
}
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
class AppTitle extends StatelessWidget {
const AppTitle({super.key, required this.text});
final String text;
@override
Widget build(BuildContext context) {
return Text(
tr(text),
textAlign: TextAlign.start,
style: Theme.of(context).textTheme.headlineLarge!.apply(fontWeightDelta: 2),
);
}
}
import 'package:flutter/material.dart';
import 'package:sortgame/utils/color_extensions.dart';
class OutlinedText extends StatelessWidget {
const OutlinedText({
super.key,
required this.text,
required this.fontSize,
required this.textColor,
this.outlineColor,
});
final String text;
final double fontSize;
final Color textColor;
final Color? outlineColor;
@override
Widget build(BuildContext context) {
final double delta = fontSize / 30;
return Text(
text,
style: TextStyle(
inherit: true,
fontSize: fontSize,
fontWeight: FontWeight.w600,
color: textColor,
shadows: [
Shadow(
offset: Offset(-delta, -delta),
color: outlineColor ?? textColor.darken(),
),
Shadow(
offset: Offset(delta, -delta),
color: outlineColor ?? textColor.darken(),
),
Shadow(
offset: Offset(delta, delta),
color: outlineColor ?? textColor.darken(),
),
Shadow(
offset: Offset(-delta, delta),
color: outlineColor ?? textColor.darken(),
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:sortgame/models/game.dart';
import 'package:sortgame/ui/widgets/helpers/outlined_text_widget.dart';
import 'package:sortgame/utils/color_extensions.dart';
class PositionIndicator extends StatelessWidget {
const PositionIndicator({super.key, required this.game});
final Game game;
@override
Widget build(BuildContext context) {
// Normalized [0..1] value
final double barValue = game.position / game.gameSettings.itemsCount;
const Color baseColor = Color.fromARGB(255, 215, 1, 133);
const barHeight = 40.0;
const Color textColor = Color.fromARGB(255, 238, 238, 238);
const Color outlineColor = Color.fromARGB(255, 200, 200, 200);
return Stack(
alignment: Alignment.center,
children: [
LinearProgressIndicator(
value: barValue,
color: baseColor,
backgroundColor: baseColor.darken(),
minHeight: barHeight,
borderRadius: const BorderRadius.all(Radius.circular(barHeight / 4)),
),
OutlinedText(
text: '${game.position}/${game.gameSettings.itemsCount}',
fontSize: 0.9 * barHeight,
textColor: textColor,
outlineColor: outlineColor,
),
],
);
}
}
import 'package:flutter/material.dart';
import 'package:sortgame/models/game.dart';
import 'package:sortgame/ui/widgets/helpers/outlined_text_widget.dart';
class ScoreIndicator extends StatelessWidget {
const ScoreIndicator({super.key, required this.game});
final Game game;
@override
Widget build(BuildContext context) {
const Color baseColor = Color.fromARGB(255, 121, 93, 246);
return OutlinedText(
text: game.score.toString(),
fontSize: 70,
textColor: baseColor,
);
}
}
import 'dart:ui';
extension ColorExtension on Color {
Color darken([int percent = 40]) {
assert(1 <= percent && percent <= 100);
final value = 1 - percent / 100;
return Color.fromARGB(
alpha,
(red * value).round(),
(green * value).round(),
(blue * value).round(),
);
}
Color lighten([int percent = 40]) {
assert(1 <= percent && percent <= 100);
final value = percent / 100;
return Color.fromARGB(
alpha,
(red + ((255 - red) * value)).round(),
(green + ((255 - green) * value)).round(),
(blue + ((255 - blue) * value)).round(),
);
}
Color avg(Color other) {
final red = (this.red + other.red) ~/ 2;
final green = (this.green + other.green) ~/ 2;
final blue = (this.blue + other.blue) ~/ 2;
final alpha = (this.alpha + other.alpha) ~/ 2;
return Color.fromARGB(alpha, red, green, blue);
}
}