diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..29a3a50
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,43 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# 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.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+**/ios/Flutter/.last_build_id
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.pub-cache/
+.pub/
+/build/
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
diff --git a/.metadata b/.metadata
new file mode 100644
index 0000000..8b82b76
--- /dev/null
+++ b/.metadata
@@ -0,0 +1,36 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: "4cf269e36de2573851eaef3c763994f8f9be494d"
+ channel: "stable"
+
+project_type: app
+
+# Tracks metadata for the flutter migrate command
+migration:
+ platforms:
+ - platform: root
+ create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
+ base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
+ - platform: android
+ create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
+ base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
+ - platform: web
+ create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
+ base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
+ - platform: windows
+ create_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
+ base_revision: 4cf269e36de2573851eaef3c763994f8f9be494d
+
+ # User provided section
+
+ # List of Local paths (relative to this file) that should be
+ # ignored by the migrate tool.
+ #
+ # Files that are not part of the templates will be ignored by default.
+ unmanaged_files:
+ - 'lib/main.dart'
+ - 'ios/Runner.xcodeproj/project.pbxproj'
diff --git a/README.md b/README.md
index b7812d4..f5da939 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1 @@
-# pmu_kursach
-
+kursach
diff --git a/analysis_options.yaml b/analysis_options.yaml
new file mode 100644
index 0000000..0d29021
--- /dev/null
+++ b/analysis_options.yaml
@@ -0,0 +1,28 @@
+# 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.dev/lints.
+ #
+ # 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
diff --git a/android/.gitignore b/android/.gitignore
new file mode 100644
index 0000000..55afd91
--- /dev/null
+++ b/android/.gitignore
@@ -0,0 +1,13 @@
+gradle-wrapper.jar
+/.gradle
+/captures/
+/gradlew
+/gradlew.bat
+/local.properties
+GeneratedPluginRegistrant.java
+
+# Remember to never publicly share your keystore.
+# See https://flutter.dev/to/reference-keystore
+key.properties
+**/*.keystore
+**/*.jks
diff --git a/android/app/build.gradle b/android/app/build.gradle
new file mode 100644
index 0000000..990750e
--- /dev/null
+++ b/android/app/build.gradle
@@ -0,0 +1,44 @@
+plugins {
+ id "com.android.application"
+ id "kotlin-android"
+ // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
+ id "dev.flutter.flutter-gradle-plugin"
+}
+
+android {
+ namespace = "com.example.kursach"
+ compileSdk = flutter.compileSdkVersion
+ ndkVersion = flutter.ndkVersion
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = JavaVersion.VERSION_1_8
+ }
+
+ defaultConfig {
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+ applicationId = "com.example.kursach"
+ // You can update the following values to match your application needs.
+ // For more information, see: https://flutter.dev/to/review-gradle-config.
+ minSdk = flutter.minSdkVersion
+ targetSdk = flutter.targetSdkVersion
+ versionCode = flutter.versionCode
+ versionName = flutter.versionName
+ }
+
+ buildTypes {
+ release {
+ // TODO: Add your own signing config for the release build.
+ // Signing with the debug keys for now, so `flutter run --release` works.
+ signingConfig = signingConfigs.debug
+ }
+ }
+}
+
+flutter {
+ source = "../.."
+}
diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/android/app/src/debug/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..1faf263
--- /dev/null
+++ b/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/kotlin/com/example/lab/MainActivity.kt b/android/app/src/main/kotlin/com/example/lab/MainActivity.kt
new file mode 100644
index 0000000..6d11753
--- /dev/null
+++ b/android/app/src/main/kotlin/com/example/lab/MainActivity.kt
@@ -0,0 +1,5 @@
+package com.example.kursach
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity: FlutterActivity()
diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml
new file mode 100644
index 0000000..f74085f
--- /dev/null
+++ b/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 0000000..304732f
--- /dev/null
+++ b/android/app/src/main/res/drawable/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..63d892c
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..313ab8e
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..172785d
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b075f5b
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..9fbeed2
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml
new file mode 100644
index 0000000..06952be
--- /dev/null
+++ b/android/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..cb1ef88
--- /dev/null
+++ b/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/android/app/src/profile/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/android/build.gradle b/android/build.gradle
new file mode 100644
index 0000000..d2ffbff
--- /dev/null
+++ b/android/build.gradle
@@ -0,0 +1,18 @@
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.buildDir = "../build"
+subprojects {
+ project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+ project.evaluationDependsOn(":app")
+}
+
+tasks.register("clean", Delete) {
+ delete rootProject.buildDir
+}
diff --git a/android/gradle.properties b/android/gradle.properties
new file mode 100644
index 0000000..2597170
--- /dev/null
+++ b/android/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..7bb2df6
--- /dev/null
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
diff --git a/android/settings.gradle b/android/settings.gradle
new file mode 100644
index 0000000..b9e43bd
--- /dev/null
+++ b/android/settings.gradle
@@ -0,0 +1,25 @@
+pluginManagement {
+ def flutterSdkPath = {
+ def properties = new Properties()
+ file("local.properties").withInputStream { properties.load(it) }
+ def flutterSdkPath = properties.getProperty("flutter.sdk")
+ assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
+ return flutterSdkPath
+ }()
+
+ includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
+
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+plugins {
+ id "dev.flutter.flutter-plugin-loader" version "1.0.0"
+ id "com.android.application" version "8.1.0" apply false
+ id "org.jetbrains.kotlin.android" version "1.8.22" apply false
+}
+
+include ":app"
diff --git a/assets/app_icon.jpg b/assets/app_icon.jpg
new file mode 100644
index 0000000..b0cd482
Binary files /dev/null and b/assets/app_icon.jpg differ
diff --git a/assets/svg/ru.svg b/assets/svg/ru.svg
new file mode 100644
index 0000000..ae12982
--- /dev/null
+++ b/assets/svg/ru.svg
@@ -0,0 +1,19 @@
+
+
+
\ No newline at end of file
diff --git a/assets/svg/uk.svg b/assets/svg/uk.svg
new file mode 100644
index 0000000..88e2211
--- /dev/null
+++ b/assets/svg/uk.svg
@@ -0,0 +1,23 @@
+
+
+
\ No newline at end of file
diff --git a/l10n.yaml b/l10n.yaml
new file mode 100644
index 0000000..810ca4a
--- /dev/null
+++ b/l10n.yaml
@@ -0,0 +1,6 @@
+arb-dir: l10n
+template-arb-file: app_ru.arb
+output-localization-file: app_locale.dart
+output-dir: lib/components/l10n
+output-class: AppLocale
+synthetic-package: false
diff --git a/l10n/app_en.arb b/l10n/app_en.arb
new file mode 100644
index 0000000..b39a396
--- /dev/null
+++ b/l10n/app_en.arb
@@ -0,0 +1,7 @@
+{
+ "@@locale": "en",
+
+ "cardLiked": "Card added in favourite",
+ "cardDisliked": "Card deleted from favourite",
+ "searchInputPlaceholder": "Search..."
+}
\ No newline at end of file
diff --git a/l10n/app_ru.arb b/l10n/app_ru.arb
new file mode 100644
index 0000000..4bacd91
--- /dev/null
+++ b/l10n/app_ru.arb
@@ -0,0 +1,7 @@
+{
+ "@@locale": "ru",
+
+ "cardLiked": "Карточка добавлена в Избранное",
+ "cardDisliked": "Карточка удалена из Избранного",
+ "searchInputPlaceholder": "Поиск..."
+}
\ No newline at end of file
diff --git a/lib/components/extensions/local_context_x.dart b/lib/components/extensions/local_context_x.dart
new file mode 100644
index 0000000..15d63d0
--- /dev/null
+++ b/lib/components/extensions/local_context_x.dart
@@ -0,0 +1,6 @@
+import 'package:flutter/cupertino.dart';
+import 'package:kursach/components/l10n/app_locale.dart';
+
+extension LocalContextX on BuildContext {
+ AppLocale get locale => AppLocale.of(this)!;
+}
diff --git a/lib/components/l10n/app_locale.dart b/lib/components/l10n/app_locale.dart
new file mode 100644
index 0000000..33fc87a
--- /dev/null
+++ b/lib/components/l10n/app_locale.dart
@@ -0,0 +1,147 @@
+import 'dart:async';
+
+import 'package:flutter/foundation.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_localizations/flutter_localizations.dart';
+import 'package:intl/intl.dart' as intl;
+
+import 'app_locale_en.dart';
+import 'app_locale_ru.dart';
+
+// ignore_for_file: type=lint
+
+/// Callers can lookup localized strings with an instance of AppLocale
+/// returned by `AppLocale.of(context)`.
+///
+/// Applications need to include `AppLocale.delegate()` in their app's
+/// `localizationDelegates` list, and the locales they support in the app's
+/// `supportedLocales` list. For example:
+///
+/// ```dart
+/// import 'l10n/app_locale.dart';
+///
+/// return MaterialApp(
+/// localizationsDelegates: AppLocale.localizationsDelegates,
+/// supportedLocales: AppLocale.supportedLocales,
+/// home: MyApplicationHome(),
+/// );
+/// ```
+///
+/// ## Update pubspec.yaml
+///
+/// Please make sure to update your pubspec.yaml to include the following
+/// packages:
+///
+/// ```yaml
+/// dependencies:
+/// # Internationalization support.
+/// flutter_localizations:
+/// sdk: flutter
+/// intl: any # Use the pinned version from flutter_localizations
+///
+/// # Rest of dependencies
+/// ```
+///
+/// ## iOS Applications
+///
+/// iOS applications define key application metadata, including supported
+/// locales, in an Info.plist file that is built into the application bundle.
+/// To configure the locales supported by your app, you’ll need to edit this
+/// file.
+///
+/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file.
+/// Then, in the Project Navigator, open the Info.plist file under the Runner
+/// project’s Runner folder.
+///
+/// Next, select the Information Property List item, select Add Item from the
+/// Editor menu, then select Localizations from the pop-up menu.
+///
+/// Select and expand the newly-created Localizations item then, for each
+/// locale your application supports, add a new item and select the locale
+/// you wish to add from the pop-up menu in the Value field. This list should
+/// be consistent with the languages listed in the AppLocale.supportedLocales
+/// property.
+abstract class AppLocale {
+ AppLocale(String locale) : localeName = intl.Intl.canonicalizedLocale(locale.toString());
+
+ final String localeName;
+
+ static AppLocale? of(BuildContext context) {
+ return Localizations.of(context, AppLocale);
+ }
+
+ static const LocalizationsDelegate delegate = _AppLocaleDelegate();
+
+ /// A list of this localizations delegate along with the default localizations
+ /// delegates.
+ ///
+ /// Returns a list of localizations delegates containing this delegate along with
+ /// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
+ /// and GlobalWidgetsLocalizations.delegate.
+ ///
+ /// Additional delegates can be added by appending to this list in
+ /// MaterialApp. This list does not have to be used at all if a custom list
+ /// of delegates is preferred or required.
+ static const List> localizationsDelegates = >[
+ delegate,
+ GlobalMaterialLocalizations.delegate,
+ GlobalCupertinoLocalizations.delegate,
+ GlobalWidgetsLocalizations.delegate,
+ ];
+
+ /// A list of this localizations delegate's supported locales.
+ static const List supportedLocales = [
+ Locale('en'),
+ Locale('ru')
+ ];
+
+ /// No description provided for @cardLiked.
+ ///
+ /// In ru, this message translates to:
+ /// **'Карточка добавлена в Избранное'**
+ String get cardLiked;
+
+ /// No description provided for @cardDisliked.
+ ///
+ /// In ru, this message translates to:
+ /// **'Карточка удалена из Избранного'**
+ String get cardDisliked;
+
+ /// No description provided for @searchInputPlaceholder.
+ ///
+ /// In ru, this message translates to:
+ /// **'Поиск...'**
+ String get searchInputPlaceholder;
+}
+
+class _AppLocaleDelegate extends LocalizationsDelegate {
+ const _AppLocaleDelegate();
+
+ @override
+ Future load(Locale locale) {
+ return SynchronousFuture(lookupAppLocale(locale));
+ }
+
+ @override
+ bool isSupported(Locale locale) => ['en', 'ru'].contains(locale.languageCode);
+
+ @override
+ bool shouldReload(_AppLocaleDelegate old) => false;
+}
+
+AppLocale lookupAppLocale(Locale locale) {
+
+
+ // Lookup logic when only language code is specified.
+ switch (locale.languageCode) {
+ case 'en': return AppLocaleEn();
+ case 'ru': return AppLocaleRu();
+ }
+
+ throw FlutterError(
+ 'AppLocale.delegate failed to load unsupported locale "$locale". This is likely '
+ 'an issue with the localizations generation tool. Please file an issue '
+ 'on GitHub with a reproducible sample app and the gen-l10n configuration '
+ 'that was used.'
+ );
+}
diff --git a/lib/components/l10n/app_locale_en.dart b/lib/components/l10n/app_locale_en.dart
new file mode 100644
index 0000000..c6084cd
--- /dev/null
+++ b/lib/components/l10n/app_locale_en.dart
@@ -0,0 +1,17 @@
+import 'app_locale.dart';
+
+// ignore_for_file: type=lint
+
+/// The translations for English (`en`).
+class AppLocaleEn extends AppLocale {
+ AppLocaleEn([String locale = 'en']) : super(locale);
+
+ @override
+ String get cardLiked => 'Card added in favourite';
+
+ @override
+ String get cardDisliked => 'Card deleted from favourite';
+
+ @override
+ String get searchInputPlaceholder => 'Search...';
+}
diff --git a/lib/components/l10n/app_locale_ru.dart b/lib/components/l10n/app_locale_ru.dart
new file mode 100644
index 0000000..7191228
--- /dev/null
+++ b/lib/components/l10n/app_locale_ru.dart
@@ -0,0 +1,17 @@
+import 'app_locale.dart';
+
+// ignore_for_file: type=lint
+
+/// The translations for Russian (`ru`).
+class AppLocaleRu extends AppLocale {
+ AppLocaleRu([String locale = 'ru']) : super(locale);
+
+ @override
+ String get cardLiked => 'Карточка добавлена в Избранное';
+
+ @override
+ String get cardDisliked => 'Карточка удалена из Избранного';
+
+ @override
+ String get searchInputPlaceholder => 'Поиск...';
+}
diff --git a/lib/components/resources/resources.g.dart b/lib/components/resources/resources.g.dart
new file mode 100644
index 0000000..cfeb1ff
--- /dev/null
+++ b/lib/components/resources/resources.g.dart
@@ -0,0 +1,12 @@
+/// Generate by [asset_generator](https://github.com/fluttercandies/flutter_asset_generator) library.
+/// PLEASE DO NOT EDIT MANUALLY.
+// ignore_for_file: constant_identifier_names
+class R {
+ const R._();
+
+ /// 
+ static const String ASSETS_SVG_RU_SVG = 'assets/svg/ru.svg';
+
+ /// 
+ static const String ASSETS_SVG_UK_SVG = 'assets/svg/uk.svg';
+}
diff --git a/lib/components/utils/debounce.dart b/lib/components/utils/debounce.dart
new file mode 100644
index 0000000..e82ea45
--- /dev/null
+++ b/lib/components/utils/debounce.dart
@@ -0,0 +1,19 @@
+import 'dart:async';
+import 'dart:ui';
+
+class Debounce {
+ factory Debounce() => _instance;
+
+ // Приватный конструктор
+ Debounce._();
+
+ static final Debounce _instance = Debounce._();
+
+ static Timer? _timer;
+
+ static void run(
+ {required VoidCallback action, Duration delay = const Duration(milliseconds: 500)}) {
+ _timer?.cancel();
+ _timer = Timer(delay, action);
+ }
+}
diff --git a/lib/data/dtos/artists_dto.dart b/lib/data/dtos/artists_dto.dart
new file mode 100644
index 0000000..097f5b8
--- /dev/null
+++ b/lib/data/dtos/artists_dto.dart
@@ -0,0 +1,47 @@
+import 'package:json_annotation/json_annotation.dart';
+
+part 'artists_dto.g.dart';
+
+// dart run build_runner build --delete-conflicting-outputs
+
+@JsonSerializable(createToJson: false)
+class ArtistsDto {
+ final List? data;
+ final MetaDto? meta;
+
+ const ArtistsDto({this.data, this.meta});
+
+ factory ArtistsDto.fromJson(Map json) => _$ArtistsDtoFromJson(json);
+}
+
+@JsonSerializable(createToJson: false)
+class MetaDto {
+ final PaginationDto? pagination;
+
+ const MetaDto({this.pagination});
+
+ factory MetaDto.fromJson(Map json) => _$MetaDtoFromJson(json);
+}
+
+@JsonSerializable(createToJson: false)
+class PaginationDto {
+ final int? current;
+ final int? next;
+ final int? last;
+
+ const PaginationDto({this.current, this.last, this.next});
+
+ factory PaginationDto.fromJson(Map json) => _$PaginationDtoFromJson(json);
+}
+
+@JsonSerializable(createToJson: false)
+class ArtistDataDto {
+ final String? id;
+ final String? name;
+ final String image;
+ final int year_streams;
+
+ const ArtistDataDto(this.id, this.name, this.image, this.year_streams);
+
+ factory ArtistDataDto.fromJson(Map json) => _$ArtistDataDtoFromJson(json);
+}
\ No newline at end of file
diff --git a/lib/data/dtos/artists_dto.g.dart b/lib/data/dtos/artists_dto.g.dart
new file mode 100644
index 0000000..dbe5362
--- /dev/null
+++ b/lib/data/dtos/artists_dto.g.dart
@@ -0,0 +1,37 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'artists_dto.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+ArtistsDto _$ArtistsDtoFromJson(Map json) => ArtistsDto(
+ data: (json['data'] as List?)
+ ?.map((e) => ArtistDataDto.fromJson(e as Map))
+ .toList(),
+ meta: json['meta'] == null
+ ? null
+ : MetaDto.fromJson(json['meta'] as Map),
+ );
+
+MetaDto _$MetaDtoFromJson(Map json) => MetaDto(
+ pagination: json['pagination'] == null
+ ? null
+ : PaginationDto.fromJson(json['pagination'] as Map),
+ );
+
+PaginationDto _$PaginationDtoFromJson(Map json) =>
+ PaginationDto(
+ current: (json['current'] as num?)?.toInt(),
+ last: (json['last'] as num?)?.toInt(),
+ next: (json['next'] as num?)?.toInt(),
+ );
+
+ArtistDataDto _$ArtistDataDtoFromJson(Map json) =>
+ ArtistDataDto(
+ json['id'] as String?,
+ json['name'] as String?,
+ json['image'] as String,
+ (json['year_streams'] as num).toInt(),
+ );
diff --git a/lib/data/mappers/characters_mapper.dart b/lib/data/mappers/characters_mapper.dart
new file mode 100644
index 0000000..fcde0c5
--- /dev/null
+++ b/lib/data/mappers/characters_mapper.dart
@@ -0,0 +1,17 @@
+import 'package:kursach/data/dtos/artists_dto.dart';
+import 'package:kursach/domain/models/card_data.dart';
+import 'package:kursach/domain/models/home_data.dart';
+
+extension ArtistDataDtoToModel on ArtistDataDto {
+ CardData toDomain() => CardData(
+ id: id,
+ name: name ?? "UNKNOWN",
+ image: "http://10.0.2.2:8080${image}",
+ year_streams: year_streams ?? 0);
+}
+
+extension ArtistsDtoToModel on ArtistsDto {
+ HomeData toDomain() => HomeData(
+ data: data?.map((e) => e.toDomain()).toList(),
+ nextPage: meta?.pagination?.next);
+}
diff --git a/lib/data/repositories/api_interface.dart b/lib/data/repositories/api_interface.dart
new file mode 100644
index 0000000..b84d9fa
--- /dev/null
+++ b/lib/data/repositories/api_interface.dart
@@ -0,0 +1,7 @@
+import 'package:kursach/domain/models/home_data.dart';
+
+typedef OnErrorCallback = void Function(String? error);
+
+abstract class ApiInterface {
+ Future loadData({OnErrorCallback? onError});
+}
diff --git a/lib/data/repositories/hiphop_repository.dart b/lib/data/repositories/hiphop_repository.dart
new file mode 100644
index 0000000..b28fa1f
--- /dev/null
+++ b/lib/data/repositories/hiphop_repository.dart
@@ -0,0 +1,43 @@
+import 'dart:developer';
+import 'package:dio/dio.dart';
+import 'package:kursach/data/dtos/artists_dto.dart';
+import 'package:kursach/data/mappers/characters_mapper.dart';
+import 'package:kursach/data/repositories/api_interface.dart';
+import 'package:kursach/domain/models/home_data.dart';
+import 'package:pretty_dio_logger/pretty_dio_logger.dart';
+
+class HipHopRepository extends ApiInterface {
+ static final Dio _dio = Dio(
+ BaseOptions(connectTimeout: const Duration(seconds: 10)))
+ ..interceptors.add(
+ PrettyDioLogger(request: true, requestHeader: true, requestBody: true));
+
+ static const String _baseUrl = "http://10.0.2.2:8080";
+
+ @override
+ Future loadData(
+ {OnErrorCallback? onError,
+ String? q,
+ int page = 1,
+ int pageSize = 10}) async {
+ try {
+ const String url = '$_baseUrl/artist/get';
+
+ final Response response = await _dio.get