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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ migrate_working_dir/
*.iws
.idea/

*.freezed.dart
*.g.dart

# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
Expand Down
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
code_gen:
flutter pub run build_runner build --delete-conflicting-outputs

avd:
./scripts/run_avd.sh
68 changes: 43 additions & 25 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,29 +1,47 @@
# 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`.
include: package:surf_lint_rules/analysis_options.yaml

# 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
analyzer:
exclude:
- "ios/**"
- "android/**"
- "build/**"
- "script/**"
- "**/*.g.dart"
- "**/*.freezed.dart"
errors:
invalid_annotation_target: ignore

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.
dart_code_metrics:
metrics:
cyclomatic-complexity: 20
maximum-nesting-level: 5
number-of-parameters: 4
source-lines-of-code: 50
number-of-methods: 10
weight-of-class: 0.33
maintainability-index: 50
anti-patterns:
- long-method
- long-parameter-list
metrics-exclude:
- test/**
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
- always-remove-listener
- avoid-unused-parameters
- avoid-unnecessary-setstate
- double-literal-format
- newline-before-return
- no-boolean-literal-compare
- prefer-conditional-expressions
- prefer-intl-name
- provide-correct-intl-args
- prefer-match-file-name:
exclude:
- lib/**
- test/**

# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
linter:
rules:
public_member_api_docs: false
always_put_required_named_parameters_first: false
always_use_package_imports: true
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ subprojects {
project.evaluationDependsOn(':app')
}

task clean(type: Delete) {
tasks.register("clean", Delete) {
delete rootProject.buildDir
}
11 changes: 8 additions & 3 deletions docs/RESULT.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
# Целевая платформа

[здесь вставьте платформу/платформы под которые вы разрабатывали, это поможет нам при проверке заданий]
Android

# Результаты

[здесь можете похвастаться, что успели реализовать, или сделали что-то сверх задания]
* Реализовать доменную модель
* Применил подход описания ValueObject с помощью библиотеки dartz. Это позволяет писать код, который не позволяет забыть обработать ситуацию что-то пошло не так
* Реализовал локальную базу данных
* Подготовил код для загрузки файлов билетов с возможностью приостановки загрузки с помощью библиотеки dio
* При решении части задач использовал chat-gpt

# Ссылки на демонстрацию работы/скриншоты

[здесь оставьте ссылки на скринкаст/скриншоты, можно в Github-репозитории или в отдельном облаке]
Вид экрана списка билетов, когда что-то пошло не так
![something-wrong.png](./presentation/something-wrong.png)
Binary file added docs/presentation/something-wrong.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions ios/Flutter/Debug.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
1 change: 1 addition & 0 deletions ios/Flutter/Release.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
44 changes: 44 additions & 0 deletions ios/Podfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '11.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}

def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end

File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end

require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)

flutter_ios_podfile_setup

target 'Runner' do
use_frameworks!
use_modular_headers!

flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end

post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end
37 changes: 37 additions & 0 deletions lib/assets/strings/locale/ru.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import 'package:surf_flutter_study_jam_2023/features/ticket_storage/domain/tickets/ticket/status/value_object.dart';
import 'dart:math' as math;

class AppStrings {
static const ticketStorage = _TicketStorageStrings();
}

class _TicketStorageStrings {
String get addButtonLabel => 'Добавить';
String get ticketsTitle => 'Хранение билетов';
String get enterUrlPlaceholder => 'Введите url';
String get emptyList => 'Здесь пока ничего нет';
String get unexpectedFailure => 'Что-то пошло не так';

const _TicketStorageStrings();

String statusTitle(TicketStatus status) {
return status.when(
initialized: () => 'Необходимо закончить редактирование',
readyToLoadFile: (_) => 'Ожидает начала загрузки',
loadingFile: (current, total) =>
'Загружается ${_formatBytes(current, 1)} из ${_formatBytes(total, 1)}',
fileLoaded: (_) => 'Файл загружен',
paused: (_) => 'Приостановлено',
);
}
}

String _formatBytes(int bytes, int decimals) {
if (bytes <= 0) return '0 B';
const suffixes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

final i = (math.log(bytes) / math.log(1024)).floor();
final bytesAsString = (bytes / math.pow(1024, i)).toStringAsFixed(decimals);

return '$bytesAsString ${suffixes[i]}';
}
88 changes: 88 additions & 0 deletions lib/assets/text/text_extension.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import 'package:flutter/material.dart';
import 'package:surf_flutter_study_jam_2023/assets/text/text_style.dart';

/// App text style scheme.
class AppTextTheme extends ThemeExtension<AppTextTheme> {
/// Text style 14_140.
final TextStyle regular14;

/// Text style 16_124.
final TextStyle regular16;

/// Text style 14_140_500.
final TextStyle medium14;

/// Text style 16_124_500.
final TextStyle medium16;

/// Text style 14_140_700.
final TextStyle bold14;

/// Text style 16_124_700.
final TextStyle bold16;

AppTextTheme._({
required this.regular14,
required this.regular16,
required this.medium14,
required this.medium16,
required this.bold14,
required this.bold16,
});

/// Base app text theme.
AppTextTheme.base()
: regular14 = AppTextStyle.regular14.value,
regular16 = AppTextStyle.regular16.value,
medium14 = AppTextStyle.medium14.value,
medium16 = AppTextStyle.medium16.value,
bold14 = AppTextStyle.bold14.value,
bold16 = AppTextStyle.bold16.value;

@override
ThemeExtension<AppTextTheme> lerp(
ThemeExtension<AppTextTheme>? other,
double t,
) {
if (other is! AppTextTheme) {
return this;
}

return copyWith(
regular14: TextStyle.lerp(regular14, other.regular14, t),
regular16: TextStyle.lerp(regular16, other.regular16, t),
medium14: TextStyle.lerp(medium14, other.medium14, t),
medium16: TextStyle.lerp(medium16, other.medium16, t),
bold14: TextStyle.lerp(bold14, other.bold14, t),
bold16: TextStyle.lerp(bold16, other.bold16, t),
);
}

@override
ThemeExtension<AppTextTheme> copyWith({
TextStyle? regular14,
TextStyle? regular16,
TextStyle? medium14,
TextStyle? medium16,
TextStyle? bold14,
TextStyle? bold16,
}) {
return AppTextTheme._(
regular14: regular14 ?? this.regular14,
regular16: regular16 ?? this.regular16,
medium14: medium14 ?? this.medium14,
medium16: medium16 ?? this.medium16,
bold14: bold14 ?? this.bold14,
bold16: bold16 ?? this.bold16,
);
}

/// Return text theme for app from context.
static AppTextTheme of(BuildContext context) {
return Theme.of(context).extension<AppTextTheme>() ??
_throwThemeExceptionFromFunc(context);
}
}

Never _throwThemeExceptionFromFunc(BuildContext context) =>
throw Exception('$AppTextTheme не найдена в $context');
19 changes: 19 additions & 0 deletions lib/assets/text/text_style.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//ignore_for_file: public_member_api_docs

import 'package:flutter/material.dart';

/// App text style.
enum AppTextStyle {
regular14(TextStyle(fontSize: 14, height: 1.4)),
regular16(TextStyle(fontSize: 16, height: 1.24)),

medium14(TextStyle(fontSize: 14, height: 1.4, fontWeight: FontWeight.w500)),
medium16(TextStyle(fontSize: 16, height: 1.24, fontWeight: FontWeight.w500)),

bold14(TextStyle(fontSize: 14, height: 1.4, fontWeight: FontWeight.w700)),
bold16(TextStyle(fontSize: 16, height: 1.24, fontWeight: FontWeight.w700));

final TextStyle value;

const AppTextStyle(this.value);
}
20 changes: 20 additions & 0 deletions lib/assets/themes/theme_data.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'package:flutter/material.dart';
import 'package:surf_flutter_study_jam_2023/assets/text/text_extension.dart';

/// Class of the app themes data.
abstract class AppThemeData {
/// Light theme configuration.
static final ThemeData lightTheme = ThemeData(
useMaterial3: true,
brightness: Brightness.light,
extensions: [_textTheme],
);

/// Dark theme configuration.
static final ThemeData darkTheme = ThemeData(
brightness: Brightness.dark,
extensions: [_textTheme],
);

static final _textTheme = AppTextTheme.base();
}
33 changes: 33 additions & 0 deletions lib/data/database.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import 'dart:io';

import 'package:drift/drift.dart';
import 'package:drift/native.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:surf_flutter_study_jam_2023/data/tickets_table.dart';

part 'database.g.dart';

@DriftDatabase(
tables: [
TicketsTable,
],
)
class AppDb extends _$AppDb {
@override
int get schemaVersion => 1;

AppDb() : super(_openConnection());
}

LazyDatabase _openConnection() {
return LazyDatabase(() async {
final dbFolder = await getApplicationDocumentsDirectory();
final file = File(p.join(dbFolder.path, 'db.sqlite'));

return NativeDatabase.createInBackground(
file,
logStatements: true,
);
});
}
Loading