Skip to content

Commit

Permalink
Merge pull request #37 from msthoma/null_safety
Browse files Browse the repository at this point in the history
Null safety
  • Loading branch information
msthoma authored Dec 21, 2021
2 parents 23aeae8 + 83ea08c commit 22060c3
Show file tree
Hide file tree
Showing 41 changed files with 2,722 additions and 3,034 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.ipynb inguist-detectable=false
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,3 @@ app.*.map.json

# Exclude sensitive information
lib/data/sensitive.dart

# Exclude tensorflow lite model files
*.tflite
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
# modern_art_app
# Mobile app for the Cypriot National Gallery of Modern Art

A Flutter application for the Cypriot National Gallery of Modern Art.
The repository contains the source code for a cross-platform mobile app (built using Flutter) for
the [Cypriot National Gallery of Modern Art](https://www.nicosia.org.cy/en-GB/discover/picture-galleries/state-gallery-of-contemporary-art/)
in Nicosia, Cyprus.

The app was built by the [BIO-SCENT](https://bioscent.cyens.org.cy/) research group at
the [CYENS Centre of Excellence](https://www.cyens.org.cy), as part of the study _"A systematic
approach for developing a robust artwork recognition framework using smartphone cameras"_ (currently
under review).

The app is able to automatically identify a number of artworks at the Gallery through the use of
computer vision, and display details about them to the user. The artwork identification is performed
on-device, using a Convolutional Neural Network (CNN) that trained using transfer learning on
MobileNet V2.

![App screenshots](assets/app_screenshots.png)
24 changes: 24 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# This file configures the analyzer to use the lint rule set from `package:lint`

# For apps, use the default set
include: package:lint/analysis_options.yaml

# Packages, that may be distributed (i.e. via pub.dev) should use the package
# version, resulting in a better pub score.
# include: package:lint/analysis_options_package.yaml

# You might want to exclude auto-generated files from dart analysis
analyzer:
exclude:
#- '**.freezed.dart'

# A list of all rules can be found at https://dart-lang.github.io/linter/lints/options/options.html
linter:
rules:
# avoid_classes_with_only_static_members: false

# Make constructors the first thing in every class
sort_constructors_first: true

# Choose wisely, but you don't have to
prefer_single_quotes: true
13 changes: 0 additions & 13 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,6 @@
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
Expand Down
4 changes: 4 additions & 0 deletions assets/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## Version 1.0.0 (2021-12-21)
- App migrated to null-safety
- Many UI improvements and bug fixes

## Version 0.12.2 (2021-02-17)
- Minor UI improvements
- New tile in settings with link to the Gallery's website
Expand Down
Binary file added assets/app_screenshots.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/tflite/MobNetNoArt500Frames_4.tflite
Binary file not shown.
40 changes: 24 additions & 16 deletions lib/data/artists_dao.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,42 @@ class ArtistsDao extends DatabaseAccessor<AppDatabase> with _$ArtistsDaoMixin {
into(artists).insertOnConflictUpdate(artist);

/// Gets a stream of all artists in the db.
Stream<List<Artist>> watchAllArtists({String languageCode = "en"}) =>
(select(artists).join([
leftOuterJoin(
artistTranslations, artistTranslations.id.equalsExp(artists.id))
])
..where(artistTranslations.languageCode.equals(languageCode)))
.map((e) {
Artist artist = e.readTable(artists);
return artist.copyWith(
Stream<List<Artist>> watchAllArtists({String languageCode = 'en'}) =>
(select(artists).join(
[
leftOuterJoin(
artistTranslations,
artistTranslations.id.equalsExp(artists.id),
)
],
)..where(artistTranslations.languageCode.equals(languageCode)))
.map(
(e) {
final Artist artist = e.readTable(artists);
return artist.copyWith(
name: e.readTable(artistTranslations).name,
biography: e.readTable(artistTranslations).biography);
}).watch();
biography: e.readTable(artistTranslations).biography,
);
},
).watch();

/// Get artist by id.
Future<Artist> getArtistById({
@required String artistId,
String languageCode = "en",
required String artistId,
String languageCode = 'en',
}) {
return ((select(artists)..where((tbl) => tbl.id.equals(artistId))).join(
[
leftOuterJoin(
artistTranslations, artistTranslations.id.equalsExp(artists.id))
artistTranslations,
artistTranslations.id.equalsExp(artists.id),
)
],
)..where(artistTranslations.languageCode.equals(languageCode)))
.map(
(e) {
Artist artist = e.readTable(artists);
ArtistTranslation translation = e.readTable(artistTranslations);
final Artist artist = e.readTable(artists);
final ArtistTranslation translation = e.readTable(artistTranslations);
return artist.copyWith(
name: translation.name,
biography: translation.biography,
Expand Down
106 changes: 68 additions & 38 deletions lib/data/artworks_dao.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,58 +14,87 @@ class ArtworksDao extends DatabaseAccessor<AppDatabase>

/// Gets a live stream of all artworks in the db (automatically emits new items
/// whenever the underlying data changes).
Stream<List<Artwork>> watchAllArtworks({String languageCode = "en"}) =>
Stream<List<Artwork>> watchAllArtworks({String languageCode = 'en'}) =>
(select(artworks).join([
leftOuterJoin(
artworkTranslations, artworkTranslations.id.equalsExp(artworks.id)),
leftOuterJoin(artistTranslations,
artistTranslations.id.equalsExp(artworks.artistId))
artworkTranslations,
artworkTranslations.id.equalsExp(artworks.id),
),
leftOuterJoin(
artistTranslations,
artistTranslations.id.equalsExp(artworks.artistId),
),
])
..where(artworkTranslations.languageCode.equals(languageCode) &
artistTranslations.languageCode.equals(languageCode)))
.map((e) => composeTranslatedArtwork(
..where(
artworkTranslations.languageCode.equals(languageCode) &
artistTranslations.languageCode.equals(languageCode),
))
.map(
(e) => composeTranslatedArtwork(
artwork: e.readTable(artworks),
artworkTranslation: e.readTable(artworkTranslations),
artistTranslation: e.readTable(artistTranslations)))
artistTranslation: e.readTable(artistTranslations),
),
)
.watch();

/// Gets a list of all [Artwork]s for a given [Artist].
Stream<List<Artwork>> watchArtworksByArtist({
@required String artistId,
String languageCode = "en",
required String artistId,
String languageCode = 'en',
}) =>
((select(artworks)..where((artwork) => artwork.artistId.equals(artistId)))
.join([
leftOuterJoin(
artworkTranslations, artworkTranslations.id.equalsExp(artworks.id)),
leftOuterJoin(artistTranslations,
artistTranslations.id.equalsExp(artworks.artistId))
])
..where(artworkTranslations.languageCode.equals(languageCode) &
artistTranslations.languageCode.equals(languageCode)))
.map((e) => composeTranslatedArtwork(
.join(
[
leftOuterJoin(
artworkTranslations,
artworkTranslations.id.equalsExp(artworks.id),
),
leftOuterJoin(
artistTranslations,
artistTranslations.id.equalsExp(artworks.artistId),
),
],
)..where(
artworkTranslations.languageCode.equals(languageCode) &
artistTranslations.languageCode.equals(languageCode),
))
.map(
(e) => composeTranslatedArtwork(
artwork: e.readTable(artworks),
artworkTranslation: e.readTable(artworkTranslations),
artistTranslation: e.readTable(artistTranslations)))
artistTranslation: e.readTable(artistTranslations),
),
)
.watch();

/// Get artwork by id.
Future<Artwork> getArtworkById({
@required String artworkId,
String languageCode = "en",
required String artworkId,
String languageCode = 'en',
}) =>
((select(artworks)..where((tbl) => tbl.id.equals(artworkId))).join([
leftOuterJoin(
artworkTranslations, artworkTranslations.id.equalsExp(artworks.id)),
leftOuterJoin(artistTranslations,
artistTranslations.id.equalsExp(artworks.artistId))
])
..where(artworkTranslations.languageCode.equals(languageCode) &
artistTranslations.languageCode.equals(languageCode)))
.map((e) => composeTranslatedArtwork(
((select(artworks)..where((tbl) => tbl.id.equals(artworkId))).join(
[
leftOuterJoin(
artworkTranslations,
artworkTranslations.id.equalsExp(artworks.id),
),
leftOuterJoin(
artistTranslations,
artistTranslations.id.equalsExp(artworks.artistId),
),
],
)..where(
artworkTranslations.languageCode.equals(languageCode) &
artistTranslations.languageCode.equals(languageCode),
))
.map(
(e) => composeTranslatedArtwork(
artwork: e.readTable(artworks),
artworkTranslation: e.readTable(artworkTranslations),
artistTranslation: e.readTable(artistTranslations)))
artistTranslation: e.readTable(artistTranslations),
),
)
.getSingle();

/// Safely insert an [Artwork] into db, with the use of an [ArtworksCompanion].
Expand All @@ -80,11 +109,12 @@ class ArtworksDao extends DatabaseAccessor<AppDatabase>
}

Artwork composeTranslatedArtwork({
Artwork artwork,
ArtworkTranslation artworkTranslation,
ArtistTranslation artistTranslation,
required Artwork artwork,
required ArtworkTranslation artworkTranslation,
required ArtistTranslation artistTranslation,
}) =>
artwork.copyWith(
name: artworkTranslation.name,
description: artworkTranslation.description,
artist: artistTranslation.name);
name: artworkTranslation.name,
description: artworkTranslation.description,
artist: artistTranslation.name,
);
Loading

0 comments on commit 22060c3

Please sign in to comment.