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
62 changes: 60 additions & 2 deletions .github/workflows/code-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ jobs:
- uses: actions/checkout@v7.0.1
- uses: actions/setup-java@v5.6.0
with:
java-version: 11
java-version: 17
distribution: temurin
- uses: subosito/flutter-action@v2.23.0
with:
flutter-version: '3.35.3'
flutter-version: '3.44.8'
cache: true

- name: Install dependencies for google_ml_kit
Expand Down Expand Up @@ -140,3 +140,61 @@ jobs:
run: brew install swiftlint
- name: Run SwiftLint on Swift code
run: swiftlint lint

build-android:
name: Build Android example without plugin KGP warnings
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v7.0.1
- uses: actions/setup-java@v5.6.0
with:
java-version: 17
distribution: temurin
- uses: subosito/flutter-action@v2.23.0
with:
flutter-version: '3.44.8'
cache: true
- name: Install dependencies
working-directory: ./packages/example
run: flutter pub get
- name: Build Android example
working-directory: ./packages/example
shell: bash
run: |
set -o pipefail
flutter build apk --debug 2>&1 | tee android-build.log
! grep -F "plugins that apply Kotlin Gradle Plugin" android-build.log

# Flutter only supports enabling AGP 9's built-in Kotlin from 3.47 onward.
# Keep this beta lane until 3.47 is stable, then pin the stable release.
build-android-built-in-kotlin:
name: Build Android example with AGP 9 built-in Kotlin
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v7.0.1
- uses: actions/setup-java@v5.6.0
with:
java-version: 21
distribution: temurin
- uses: subosito/flutter-action@v2.23.0
with:
flutter-version: '3.47.0-0.2.pre'
channel: beta
cache: true
- name: Enable AGP 9 built-in Kotlin
working-directory: ./packages/example
shell: bash
run: |
perl -pi -e 's/version "8\.13\.0"/version "9.3.1"/' android/settings.gradle.kts
perl -pi -e 's/gradle-8\.14\.3-all\.zip/gradle-9.6.1-all.zip/' android/gradle/wrapper/gradle-wrapper.properties
perl -pi -e 's/android\.builtInKotlin=false/android.builtInKotlin=true/' android/gradle.properties
- name: Install dependencies
working-directory: ./packages/example
run: flutter pub get
- name: Build Android example
working-directory: ./packages/example
shell: bash
run: |
set -o pipefail
flutter build apk --debug 2>&1 | tee android-build.log
! grep -E 'plugins that apply Kotlin Gradle Plugin|applies the Kotlin Gradle Plugin|KGP\) was unsuccessful' android-build.log
13 changes: 7 additions & 6 deletions packages/example/android/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
plugins {
id("com.android.application")
id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
// The Flutter Gradle Plugin must be applied after the Android Gradle plugin.
id("dev.flutter.flutter-gradle-plugin")
}

Expand All @@ -14,10 +13,6 @@ android {
targetCompatibility = JavaVersion.VERSION_11
}

kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
}

defaultConfig {
applicationId = "com.google.ml.kit.flutter.example"
minSdk = 26
Expand All @@ -37,6 +32,12 @@ android {
}
}

kotlin {
compilerOptions {
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11
}
}

dependencies {
// Add language package you need to use
implementation("com.google.mlkit:text-recognition-chinese:16.0.1")
Expand Down
3 changes: 2 additions & 1 deletion packages/example/android/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true
android.enableJetifier=true
android.newDsl=false
android.builtInKotlin=false
69 changes: 40 additions & 29 deletions packages/example/lib/activity_indicator/activity_indicator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@
import 'package:flutter/material.dart';

class Toast {
void show(String message, Future<String> t, BuildContext context,
State<StatefulWidget> state) async {
void show(
String message,
Future<String> t,
BuildContext context,
State<StatefulWidget> state,
) async {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
showLoadingIndicator(context, message);
final verificationResult = await t;
Navigator.of(context).pop();
if (!state.mounted) return;
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Result: ${verificationResult.toString()}'),
));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Result: ${verificationResult.toString()}')),
);
}

void showLoadingIndicator(BuildContext context, String text) {
Expand All @@ -22,13 +26,15 @@ class Toast {
barrierDismissible: false,
builder: (BuildContext context) {
return PopScope(
canPop: false,
child: AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8.0))),
backgroundColor: Colors.black87,
content: LoadingIndicator(text: text),
));
canPop: false,
child: AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8.0)),
),
backgroundColor: Colors.black87,
content: LoadingIndicator(text: text),
),
);
},
);
}
Expand All @@ -42,31 +48,36 @@ class LoadingIndicator extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(16),
color: Colors.black.withAlpha(204),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [_getLoadingIndicator(), _getHeading(), _getText(text)]));
padding: EdgeInsets.all(16),
color: Colors.black.withAlpha(204),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [_getLoadingIndicator(), _getHeading(), _getText(text)],
),
);
}

Widget _getLoadingIndicator() {
return Padding(
padding: EdgeInsets.only(bottom: 16),
child: SizedBox(
width: 32,
height: 32,
child: CircularProgressIndicator(strokeWidth: 3)));
padding: EdgeInsets.only(bottom: 16),
child: SizedBox(
width: 32,
height: 32,
child: CircularProgressIndicator(strokeWidth: 3),
),
);
}

Widget _getHeading() {
return Padding(
padding: EdgeInsets.only(bottom: 4),
child: Text(
'Please wait …',
style: TextStyle(color: Colors.white, fontSize: 16),
textAlign: TextAlign.center,
));
padding: EdgeInsets.only(bottom: 4),
child: Text(
'Please wait …',
style: TextStyle(color: Colors.white, fontSize: 16),
textAlign: TextAlign.center,
),
);
}

Widget _getText(String displayedText) {
Expand Down
83 changes: 46 additions & 37 deletions packages/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,7 @@ Future<void> main() async {
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Home(),
);
return MaterialApp(debugShowCheckedModeBanner: false, home: Home());
}
}

Expand All @@ -57,7 +54,9 @@ class Home extends StatelessWidget {
CustomCard('Face Detection', FaceDetectorView()),
if (Platform.isAndroid)
CustomCard(
'Face Mesh Detection', FaceMeshDetectorView()),
'Face Mesh Detection',
FaceMeshDetectorView(),
),
CustomCard('Image Labeling', ImageLabelView()),
CustomCard('Object Detection', ObjectDetectorView()),
CustomCard('Text Recognition', TextRecognizerView()),
Expand All @@ -69,39 +68,49 @@ class Home extends StatelessWidget {
CustomCard('Document Scanner', DocumentScannerView()),
if (Platform.isAndroid)
CustomCard(
'Subject Segmentation', SubjectSegmenterView())
'Subject Segmentation',
SubjectSegmenterView(),
),
],
),
SizedBox(
height: 20,
),
SizedBox(height: 20),
ExpansionTile(
title: const Text('Natural Language APIs'),
children: [
CustomCard('Language ID', LanguageIdentifierView()),
CustomCard(
'On-device Translation', LanguageTranslatorView()),
'On-device Translation',
LanguageTranslatorView(),
),
CustomCard('Smart Reply', SmartReplyView()),
CustomCard('Entity Extraction', EntityExtractionView()),
],
),
SizedBox(
height: 20,
),
SizedBox(height: 20),
if (Platform.isAndroid)
ExpansionTile(
title: const Text('GenAI APIs'),
children: [
CustomCard('Summarization',
_GenAIPlaceholderView('Summarization')),
CustomCard('Proofreading',
_GenAIPlaceholderView('Proofreading')),
CustomCard(
'Rewriting', _GenAIPlaceholderView('Rewriting')),
CustomCard('Image Description',
_GenAIPlaceholderView('Image Description')),
CustomCard('Speech Recognition',
_GenAIPlaceholderView('Speech Recognition')),
'Summarization',
_GenAIPlaceholderView('Summarization'),
),
CustomCard(
'Proofreading',
_GenAIPlaceholderView('Proofreading'),
),
CustomCard(
'Rewriting',
_GenAIPlaceholderView('Rewriting'),
),
CustomCard(
'Image Description',
_GenAIPlaceholderView('Image Description'),
),
CustomCard(
'Speech Recognition',
_GenAIPlaceholderView('Speech Recognition'),
),
CustomCard('Prompt', _GenAIPlaceholderView('Prompt')),
],
),
Expand All @@ -123,20 +132,14 @@ class _GenAIPlaceholderView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('$featureName (GenAI)'),
),
appBar: AppBar(title: Text('$featureName (GenAI)')),
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.info_outline,
size: 64,
color: Colors.blue,
),
Icon(Icons.info_outline, size: 64, color: Colors.blue),
SizedBox(height: 16),
Text(
'$featureName API',
Expand All @@ -152,9 +155,9 @@ class _GenAIPlaceholderView extends StatelessWidget {
Text(
'Implementation coming soon.',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
fontStyle: FontStyle.italic,
),
style: Theme.of(
context,
).textTheme.bodySmall?.copyWith(fontStyle: FontStyle.italic),
),
],
),
Expand Down Expand Up @@ -184,12 +187,18 @@ class CustomCard extends StatelessWidget {
),
onTap: () {
if (!featureCompleted) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content:
const Text('This feature has not been implemented yet')));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text(
'This feature has not been implemented yet',
),
),
);
} else {
Navigator.push(
context, MaterialPageRoute(builder: (context) => _viewPage));
context,
MaterialPageRoute(builder: (context) => _viewPage),
);
}
},
),
Expand Down
Loading
Loading