├── .gitignore
├── .metadata
├── LICENSE.md
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── lv
│ │ │ │ └── daria
│ │ │ │ └── example
│ │ │ │ └── bunny_search
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable-hdpi
│ │ │ ├── ic_launcher_background.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── drawable-mdpi
│ │ │ ├── ic_launcher_background.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── drawable-v21
│ │ │ ├── background.png
│ │ │ └── launch_background.xml
│ │ │ ├── drawable-xhdpi
│ │ │ ├── ic_launcher_background.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── drawable-xxhdpi
│ │ │ ├── ic_launcher_background.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── drawable-xxxhdpi
│ │ │ ├── ic_launcher_background.png
│ │ │ └── ic_launcher_foreground.png
│ │ │ ├── drawable
│ │ │ ├── background.png
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ └── ic_launcher.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── values-night
│ │ │ └── styles.xml
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── data
├── .gitignore
├── .metadata
├── lib
│ ├── brands
│ │ ├── persisted_brands_repository.dart
│ │ └── search_service.dart
│ ├── database
│ │ ├── brands_dao.dart
│ │ ├── database.dart
│ │ ├── database.g.dart
│ │ ├── list_type_converter.dart
│ │ └── model
│ │ │ ├── brand_entity.dart
│ │ │ ├── brand_with_organization_entity.dart
│ │ │ └── organization_entity.dart
│ ├── organizations
│ │ ├── model
│ │ │ ├── firebase_organization.dart
│ │ │ └── firebase_organization_brand.dart
│ │ └── repository
│ │ │ ├── assets_organizations_repository.dart
│ │ │ └── firebase_organizations_repository.dart
│ └── storage
│ │ └── shared_preferences_key_value_storage.dart
├── pubspec.lock
└── pubspec.yaml
├── domain
├── .gitignore
├── .metadata
├── lib
│ ├── brands
│ │ ├── model
│ │ │ └── brand.dart
│ │ └── repository
│ │ │ └── brands_repository.dart
│ ├── organizations
│ │ ├── model
│ │ │ ├── organization.dart
│ │ │ ├── organization_brand.dart
│ │ │ └── organization_type.dart
│ │ └── repository
│ │ │ └── organizations_repository.dart
│ ├── result
│ │ ├── delayed_result.dart
│ │ └── result.dart
│ └── storage
│ │ └── key_value_storage.dart
├── pubspec.lock
└── pubspec.yaml
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ └── Icon-App-83.5x83.5@2x.png
│ ├── LaunchBackground.imageset
│ │ ├── Contents.json
│ │ └── background.png
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
├── lib
├── analytics
│ ├── bloc_error_delegate.dart
│ └── crashlytics_fimber_tree.dart
├── app.dart
├── app_routes.dart
├── brand
│ ├── bloc
│ │ └── popular_brands_bloc.dart
│ └── widget
│ │ ├── brand_details_page.dart
│ │ ├── brand_list_item.dart
│ │ └── popular_brands_page.dart
├── generated
│ ├── codegen_loader.g.dart
│ └── locale_keys.g.dart
├── home
│ ├── bloc
│ │ └── home_bloc.dart
│ └── widget
│ │ ├── background_wave_clipper.dart
│ │ ├── home_brands_list.dart
│ │ ├── home_content_screen.dart
│ │ ├── home_organizations_section.dart
│ │ ├── home_page.dart
│ │ ├── home_popular_brands_section.dart
│ │ ├── home_splash_screen.dart
│ │ ├── no_overscroll_behaviour.dart
│ │ ├── organizations_list.dart
│ │ ├── search_bar.dart
│ │ ├── search_bunny_icon_clipper.dart
│ │ ├── show_all_button.dart
│ │ ├── sliver_search_app_bar.dart
│ │ └── support_dialog.dart
├── main.dart
├── organization
│ ├── bloc
│ │ ├── organization_brands_bloc.dart
│ │ └── organizations_bloc.dart
│ ├── model
│ │ ├── organization_brand_details.dart
│ │ ├── organization_details.dart
│ │ └── organizations_mapper.dart
│ └── widget
│ │ ├── organization_brands_page.dart
│ │ ├── organization_list_card.dart
│ │ └── organizations_page.dart
├── theme
│ ├── app_colors.dart
│ ├── app_typography.dart
│ ├── bunny_appbar_back_button.dart
│ ├── bunny_back_button.dart
│ ├── bunny_cached_logo_image.dart
│ ├── bunny_snack_bar.dart
│ └── images_provider.dart
└── utils
│ ├── cache
│ └── image_cache_manager.dart
│ └── widget
│ └── focus_utils.dart
├── pubspec.lock
├── pubspec.yaml
├── resources
├── database
│ └── bunny-search-database.json
├── fonts
│ ├── Inter-Black.ttf
│ ├── Inter-Bold.ttf
│ ├── Inter-ExtraBold.ttf
│ ├── Inter-ExtraLight.ttf
│ ├── Inter-Light.ttf
│ ├── Inter-Medium.ttf
│ ├── Inter-Regular.ttf
│ ├── Inter-SemiBold.ttf
│ └── Inter-Thin.ttf
├── icons
│ ├── background.png
│ ├── foreground.png
│ ├── ic_back.svg
│ ├── ic_bunny.png
│ ├── ic_check.svg
│ ├── ic_chevron_right.svg
│ ├── ic_cross.svg
│ ├── ic_leaping_bunny.png
│ ├── ic_question.svg
│ ├── ic_stop.svg
│ └── launcher.png
├── images
│ ├── 2.0x
│ │ ├── ic_bunny_search.png
│ │ └── ic_peta.png
│ ├── 3.0x
│ │ ├── ic_bunny_search.png
│ │ └── ic_peta.png
│ ├── ic_bunny_search.png
│ └── ic_peta.png
├── langs
│ ├── en.json
│ └── ru.json
├── scripts
│ ├── clean.sh
│ ├── generate_icons.sh
│ ├── generate_json_models.sh
│ ├── generate_splash.sh
│ ├── run_clean.sh
│ ├── run_generate_json_models.sh
│ └── update_translations.sh
└── splash
│ └── splash_bg.png
└── test
└── data
└── brands
└── search_service_test.dart
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | /build/
33 |
34 | # Web related
35 | lib/generated_plugin_registrant.dart
36 |
37 | # Symbolication related
38 | app.*.symbols
39 |
40 | # Obfuscation related
41 | app.*.map.json
42 |
43 | # Android Studio will place build artifacts here
44 | /android/app/debug
45 | /android/app/profile
46 | /android/app/release
47 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: b1395592de68cc8ac4522094ae59956dd21a91db
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # License
2 |
3 | ## “Commons Clause” License Condition v1.0
4 |
5 | The Software is provided to you by the Licensor under the License, as defined below, subject to the following condition. Without limiting other conditions in the License, the grant of rights under the License will not include, and the License does not grant to you, the right to Sell the Software. For purposes of the foregoing, “Sell” means practicing any or all of the rights granted to you under the License to provide to third parties, for a fee or other consideration (including without limitation fees for hosting or consulting/ support services related to the Software), a product or service whose value derives, entirely or substantially, from the functionality of the Software. Any license notice or attribution required by the License must also include this Commons Clause License Condition notice.
6 |
7 | Software: Bunny Search
8 |
9 | License: The 3-Clause BSD License
10 |
11 | Licensor: Darja Orlova
12 |
13 | ## The 3-Clause BSD License
14 |
15 | Copyright 2022 Darja Orlova
16 |
17 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
18 |
19 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
20 |
21 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
22 |
23 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
24 |
25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Bunny Search App
2 |
3 | This is the copy of the source code of the “Bunny Search” app.
4 |
5 | The only difference of this copy with the original is that it uses local database read from a json
6 | file, instead of Firebase. The code used in the original copy can be found by searching the comment
7 | “Used in real app”.
8 |
9 | ## Articles
10 |
11 | Flutter pet project roadmap **[based on Bunny Search](https://medium.com/@daria.orlova/flutter-pet-project-roadmap-31247c8eb015)**.
12 |
13 | Custom shaped AppBar **[as seen in the Bunny Search app](https://medium.com/flutter-community/custom-shaped-appbar-as-seen-in-the-bunny-search-app-6312d067485c)**.
14 |
15 | How to implement "fuzzy search" **[as in Bunny search app](https://dariadroid.substack.com/p/implementing-fuzzy-search-in-a-flutter)**.
16 |
17 | ## Contact me
18 |
19 | You can reach out to me via [Twitter](https://twitter.com/dariadroid) if you have any questions.
20 |
21 | ## Download app
22 |
23 | You can download the app
24 | for [android](https://play.google.com/store/apps/details?id=lv.chi.bunny_search)
25 | & [ios](https://apps.apple.com/lv/app/bunny-search/id1592571643).
26 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 |
3 | analyzer:
4 | exclude:
5 | - [ build/** ]
6 | - data/lib/**/*.g.dart #TODO and other codegen places
7 |
8 | linter:
9 | rules:
10 | - require_trailing_commas
11 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 34
30 |
31 | sourceSets {
32 | main.java.srcDirs += 'src/main/kotlin'
33 | }
34 |
35 | defaultConfig {
36 | applicationId "lv.daria.example.bunny_search"
37 | minSdkVersion 21
38 | targetSdkVersion 34
39 | versionCode flutterVersionCode.toInteger()
40 | versionName flutterVersionName
41 | }
42 |
43 | buildTypes {
44 | release {
45 | // TODO: Add your own signing config for the release build.
46 | // Signing with the debug keys for now, so `flutter run --release` works.
47 | signingConfig signingConfigs.debug
48 | }
49 | }
50 | }
51 |
52 | flutter {
53 | source '../..'
54 | }
55 |
56 | dependencies {
57 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
58 |
59 | implementation platform('com.google.firebase:firebase-bom:28.2.0')
60 | implementation 'com.google.firebase:firebase-analytics-ktx'
61 | }
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
14 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
29 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/lv/daria/example/bunny_search/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package lv.daria.example.bunny_search
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-hdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darjaorlova/bunny-search-source-code/137ef5ff61fba39768097b829a551a0c167176be/android/app/src/main/res/drawable-hdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darjaorlova/bunny-search-source-code/137ef5ff61fba39768097b829a551a0c167176be/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-mdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darjaorlova/bunny-search-source-code/137ef5ff61fba39768097b829a551a0c167176be/android/app/src/main/res/drawable-mdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darjaorlova/bunny-search-source-code/137ef5ff61fba39768097b829a551a0c167176be/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darjaorlova/bunny-search-source-code/137ef5ff61fba39768097b829a551a0c167176be/android/app/src/main/res/drawable-v21/background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darjaorlova/bunny-search-source-code/137ef5ff61fba39768097b829a551a0c167176be/android/app/src/main/res/drawable-xhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darjaorlova/bunny-search-source-code/137ef5ff61fba39768097b829a551a0c167176be/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darjaorlova/bunny-search-source-code/137ef5ff61fba39768097b829a551a0c167176be/android/app/src/main/res/drawable-xxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darjaorlova/bunny-search-source-code/137ef5ff61fba39768097b829a551a0c167176be/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darjaorlova/bunny-search-source-code/137ef5ff61fba39768097b829a551a0c167176be/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darjaorlova/bunny-search-source-code/137ef5ff61fba39768097b829a551a0c167176be/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darjaorlova/bunny-search-source-code/137ef5ff61fba39768097b829a551a0c167176be/android/app/src/main/res/drawable/background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darjaorlova/bunny-search-source-code/137ef5ff61fba39768097b829a551a0c167176be/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darjaorlova/bunny-search-source-code/137ef5ff61fba39768097b829a551a0c167176be/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darjaorlova/bunny-search-source-code/137ef5ff61fba39768097b829a551a0c167176be/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darjaorlova/bunny-search-source-code/137ef5ff61fba39768097b829a551a0c167176be/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/darjaorlova/bunny-search-source-code/137ef5ff61fba39768097b829a551a0c167176be/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
16 |
19 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
16 |
19 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.5.20'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.4.2'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | jcenter()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | tasks.register("clean", Delete) {
30 | delete rootProject.buildDir
31 | }
32 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip
7 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/data/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .flutter-plugins-dependencies
28 | .packages
29 | .pub-cache/
30 | .pub/
31 | build/
32 |
33 | # Android related
34 | **/android/**/gradle-wrapper.jar
35 | **/android/.gradle
36 | **/android/captures/
37 | **/android/gradlew
38 | **/android/gradlew.bat
39 | **/android/local.properties
40 | **/android/**/GeneratedPluginRegistrant.java
41 |
42 | # iOS/XCode related
43 | **/ios/**/*.mode1v3
44 | **/ios/**/*.mode2v3
45 | **/ios/**/*.moved-aside
46 | **/ios/**/*.pbxuser
47 | **/ios/**/*.perspectivev3
48 | **/ios/**/*sync/
49 | **/ios/**/.sconsign.dblite
50 | **/ios/**/.tags*
51 | **/ios/**/.vagrant/
52 | **/ios/**/DerivedData/
53 | **/ios/**/Icon?
54 | **/ios/**/Pods/
55 | **/ios/**/.symlinks/
56 | **/ios/**/profile
57 | **/ios/**/xcuserdata
58 | **/ios/.generated/
59 | **/ios/Flutter/App.framework
60 | **/ios/Flutter/Flutter.framework
61 | **/ios/Flutter/Flutter.podspec
62 | **/ios/Flutter/Generated.xcconfig
63 | **/ios/Flutter/app.flx
64 | **/ios/Flutter/app.zip
65 | **/ios/Flutter/flutter_assets/
66 | **/ios/Flutter/flutter_export_environment.sh
67 | **/ios/ServiceDefinitions.json
68 | **/ios/Runner/GeneratedPluginRegistrant.*
69 |
70 | # Exceptions to above rules.
71 | !**/ios/**/default.mode1v3
72 | !**/ios/**/default.mode2v3
73 | !**/ios/**/default.pbxuser
74 | !**/ios/**/default.perspectivev3
75 |
--------------------------------------------------------------------------------
/data/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: b1395592de68cc8ac4522094ae59956dd21a91db
8 | channel: stable
9 |
10 | project_type: package
11 |
--------------------------------------------------------------------------------
/data/lib/brands/search_service.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:data/database/model/brand_entity.dart';
4 | import 'package:equatable/equatable.dart';
5 | import 'package:flutter/foundation.dart';
6 |
7 | class SearchService {
8 | Future> search({
9 | required List allBrands,
10 | required String query,
11 | }) async =>
12 | compute(
13 | searchSync,
14 | SearchQuery(allBrands, query),
15 | );
16 |
17 | @visibleForTesting
18 | static List searchSync(SearchQuery query) {
19 | final searchTerm = query.query.toLowerCase();
20 | final filtered = query.allBrands.expand((brand) {
21 | final title = brand.title.toLowerCase();
22 | if (title == searchTerm) {
23 | return [SearchResult(0, brand)];
24 | }
25 | if (title.contains(searchTerm)) {
26 | return [SearchResult(1, brand)];
27 | }
28 | final maxDistance = title.length > 7 ? 4 : 2;
29 | final nameDistance = levenshteinDistance(title, searchTerm, maxDistance);
30 | if (nameDistance <= maxDistance) {
31 | return [SearchResult(nameDistance, brand)];
32 | } else {
33 | return [];
34 | }
35 | }).toList();
36 | filtered.sort((a, b) {
37 | return a.distance.compareTo(b.distance);
38 | });
39 | return filtered.map((result) => result.brand).toList();
40 | }
41 |
42 | @visibleForTesting
43 | static int levenshteinDistance(String a, String b, int maxDistance) {
44 | if (a == b) {
45 | return 0;
46 | }
47 | if (a.isEmpty) {
48 | return b.length <= maxDistance ? b.length : maxDistance + 1;
49 | }
50 | if (b.isEmpty) {
51 | return a.length <= maxDistance ? a.length : maxDistance + 1;
52 | }
53 |
54 | int aLength = a.length;
55 | int bLength = b.length;
56 | List> matrix = List.generate(
57 | bLength + 1,
58 | (i) => List.generate(aLength + 1, (j) => 0, growable: false),
59 | growable: false,
60 | );
61 |
62 | for (int i = 0; i <= aLength; i++) {
63 | matrix[0][i] = i;
64 | }
65 | for (int i = 0; i <= bLength; i++) {
66 | matrix[i][0] = i;
67 | }
68 |
69 | for (int i = 1; i <= bLength; i++) {
70 | int minRowValue = maxDistance + 1;
71 | for (int j = 1; j <= aLength; j++) {
72 | int cost = (a[j - 1] == b[i - 1]) ? 0 : 1;
73 | matrix[i][j] = _min(
74 | matrix[i - 1][j] + 1, // deletion
75 | matrix[i][j - 1] + 1, // insertion
76 | matrix[i - 1][j - 1] + cost, // substitution
77 | );
78 |
79 | minRowValue = min(minRowValue, matrix[i][j]);
80 | }
81 |
82 | if (minRowValue > maxDistance) {
83 | return maxDistance + 1;
84 | }
85 | }
86 |
87 | return matrix[bLength][aLength];
88 | }
89 |
90 | static int _min(int a, int b, int c) {
91 | return (a < b) ? (a < c ? a : c) : (b < c ? b : c);
92 | }
93 |
94 | @visibleForTesting
95 | static int hammingDistance(String a, String b) {
96 | if (a.length != b.length) {
97 | throw ArgumentError('Strings must be of equal length');
98 | }
99 |
100 | int distance = 0;
101 | for (int i = 0; i < a.length; i++) {
102 | if (a[i] != b[i]) {
103 | distance++;
104 | }
105 | }
106 | return distance;
107 | }
108 | }
109 |
110 | // TODO: Update to Dart 3 & use records
111 | class SearchQuery extends Equatable {
112 | final List allBrands;
113 | final String query;
114 |
115 | const SearchQuery(this.allBrands, this.query);
116 |
117 | @override
118 | List