Add kanji page
This commit is contained in:
parent
a8b0f3b737
commit
c1ccbc00b3
|
@ -43,8 +43,8 @@ android {
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId "com.example.tangocard_reader"
|
applicationId "xyz.h7x4.tangocard_reader"
|
||||||
minSdkVersion 16
|
minSdkVersion 26
|
||||||
targetSdkVersion 30
|
targetSdkVersion 30
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:tangocard_reader/models/yokutango_entry.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tangocard_reader/models/data_entry.dart';
|
||||||
|
|
||||||
class Flashcard extends StatelessWidget {
|
class Flashcard extends StatelessWidget {
|
||||||
final YokutangoEntry? card;
|
final YokutangoEntry? card;
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
part 'yokutango_entry.dart';
|
||||||
|
part 'kanji_entry.dart';
|
||||||
|
|
||||||
|
abstract class DataEntry {
|
||||||
|
const DataEntry();
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
part of 'data_entry.dart';
|
||||||
|
|
||||||
|
class KanjiEntry extends DataEntry {
|
||||||
|
final String kanji;
|
||||||
|
final List<WordConstruct> kana;
|
||||||
|
|
||||||
|
KanjiEntry.fromJson(Map<String, dynamic> json)
|
||||||
|
: kanji = json['kanji'] as String,
|
||||||
|
kana = [
|
||||||
|
for (final j in json['kana'] as List) WordConstruct.fromJson(j)
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return '$kanji - ${kana.join('、')}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WordConstruct {
|
||||||
|
final List<WordPiece> pieces;
|
||||||
|
|
||||||
|
WordConstruct({required this.pieces});
|
||||||
|
|
||||||
|
WordConstruct.fromJson(dynamic json)
|
||||||
|
: pieces = (json is String)
|
||||||
|
? [WordPiece(word: json, isActive: true)]
|
||||||
|
: [for (final j in json as List) WordPiece.fromJson(j)];
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return pieces.map((p) => p.isActive ? p.word : '(${p.word})').join('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WordPiece {
|
||||||
|
final String? kana;
|
||||||
|
final String? romaji;
|
||||||
|
final String word;
|
||||||
|
final bool isActive;
|
||||||
|
|
||||||
|
const WordPiece({
|
||||||
|
required this.word,
|
||||||
|
this.kana,
|
||||||
|
this.romaji,
|
||||||
|
this.isActive = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
WordPiece.fromJson(Map<String, dynamic> json)
|
||||||
|
: kana = json['kana'] as String?,
|
||||||
|
romaji = json['romaji'] as String?,
|
||||||
|
word = json['text'] as String,
|
||||||
|
isActive = json['active'] as bool? ?? false;
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:tangocard_reader/models/yokutango_entry.dart';
|
import 'data_entry.dart';
|
||||||
|
|
||||||
class BenkyouArgs {
|
class BenkyouArgs {
|
||||||
final List<YokutangoEntry> cards;
|
final List<DataEntry> cards;
|
||||||
final int? index;
|
final int? index;
|
||||||
|
|
||||||
const BenkyouArgs({required this.cards, this.index});
|
const BenkyouArgs({required this.cards, this.index});
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
class YokutangoEntry {
|
part of 'data_entry.dart';
|
||||||
|
|
||||||
|
class YokutangoEntry extends DataEntry {
|
||||||
final List<JapaneseWord> japanese;
|
final List<JapaneseWord> japanese;
|
||||||
final List<NorwegianWord> norwegian;
|
final List<NorwegianWord> norwegian;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:tangocard_reader/models/data_entry.dart';
|
||||||
import 'package:tangocard_reader/models/router_args.dart';
|
import 'package:tangocard_reader/models/router_args.dart';
|
||||||
import 'package:tangocard_reader/screens/flashcard.dart';
|
import 'package:tangocard_reader/screens/practise/flashcard.dart';
|
||||||
import 'package:tangocard_reader/screens/home.dart';
|
import 'package:tangocard_reader/screens/home.dart';
|
||||||
import 'package:tangocard_reader/screens/tango_list.dart';
|
import 'package:tangocard_reader/screens/pages/tango_list.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'screens/pages/kanji_list.dart';
|
||||||
|
|
||||||
class PageRouter {
|
class PageRouter {
|
||||||
static Route<dynamic> generateRoute(RouteSettings settings) {
|
static Route<dynamic> generateRoute(RouteSettings settings) {
|
||||||
final args = settings.arguments;
|
final args = settings.arguments;
|
||||||
|
@ -14,22 +17,41 @@ class PageRouter {
|
||||||
case '/':
|
case '/':
|
||||||
return MaterialPageRoute(builder: (_) => const Home());
|
return MaterialPageRoute(builder: (_) => const Home());
|
||||||
|
|
||||||
case '/tangolist':
|
case '/list/tango':
|
||||||
final file = args as File;
|
final file = args as File;
|
||||||
return MaterialPageRoute(builder: (_) => TangoList(file: file));
|
return MaterialPageRoute(builder: (_) => TangoList(file: file));
|
||||||
|
|
||||||
case '/benkyou':
|
case '/list/kanji':
|
||||||
|
final file = args as File;
|
||||||
|
return MaterialPageRoute(builder: (_) => KanjiList(file: file));
|
||||||
|
|
||||||
|
case '/benkyou/tango':
|
||||||
final benkyouArgs = args as BenkyouArgs;
|
final benkyouArgs = args as BenkyouArgs;
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(
|
||||||
builder: (_) => FlashcardView(
|
builder: (_) => FlashcardView(
|
||||||
cards: benkyouArgs.cards,
|
cards: benkyouArgs.cards as List<YokutangoEntry>,
|
||||||
index: benkyouArgs.index,
|
index: benkyouArgs.index,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
case '/benkyou/kanji':
|
||||||
|
// final benkyouArgs = args as BenkyouArgs;
|
||||||
|
// return MaterialPageRoute(
|
||||||
|
// builder: (_) => FlashcardView(
|
||||||
|
// cards: benkyouArgs.cards as List<YokutangoEntry>,
|
||||||
|
// index: benkyouArgs.index,
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute(
|
||||||
builder: (_) => const Text("ERROR: this route does not exist"));
|
builder: (_) => Scaffold(
|
||||||
|
appBar: AppBar(title: const Text('Error')),
|
||||||
|
body: Center(
|
||||||
|
child: ErrorWidget('No such route...')
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,81 +1,37 @@
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:tangocard_reader/models/yokutango_entry.dart';
|
|
||||||
import 'package:tangocard_reader/screens/error.dart';
|
|
||||||
import 'package:tangocard_reader/screens/loading.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:tangocard_reader/service/tangocard_files.dart';
|
||||||
|
|
||||||
class Home extends StatelessWidget {
|
import 'pages/tango_set_list.dart';
|
||||||
|
|
||||||
|
class Home extends StatefulWidget {
|
||||||
const Home({Key? key}) : super(key: key);
|
const Home({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
State<Home> createState() => _HomeState();
|
||||||
return Scaffold(
|
}
|
||||||
|
|
||||||
|
class _HomeState extends State<Home> {
|
||||||
|
int page = 0;
|
||||||
|
|
||||||
|
final _pages = [
|
||||||
|
TangoSetList(files: tangocardFilePaths, route: '/list/tango',),
|
||||||
|
TangoSetList(files: kanjicardFilePaths, route: '/list/kanji',),
|
||||||
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text("よく単語"),
|
title: const Text("よく単語"),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
),
|
),
|
||||||
body: const TangocardList());
|
body: _pages[page],
|
||||||
}
|
bottomNavigationBar: BottomNavigationBar(
|
||||||
}
|
onTap: (int index) => setState(() => page = index),
|
||||||
|
currentIndex: page,
|
||||||
class TangocardList extends StatelessWidget {
|
items: const [
|
||||||
const TangocardList({Key? key}) : super(key: key);
|
BottomNavigationBarItem(label: 'Tango', icon: Icon(Icons.style)),
|
||||||
|
BottomNavigationBarItem(label: 'Kanji', icon: Text('漢字')),
|
||||||
Future<Map<File, List<YokutangoEntry>>> get tangocardFilePaths => rootBundle
|
],
|
||||||
.loadString('AssetManifest.json')
|
),
|
||||||
.then(
|
);
|
||||||
(json) => jsonDecode(json)
|
|
||||||
.keys
|
|
||||||
.where((String key) =>
|
|
||||||
key.contains('yokutango/json/') && key.contains('.json'))
|
|
||||||
.toList(),
|
|
||||||
)
|
|
||||||
.then(
|
|
||||||
(l) async => Map.fromIterables(
|
|
||||||
l.map<File>((f) => File(f)),
|
|
||||||
await Future.wait<List<YokutangoEntry>>(
|
|
||||||
l
|
|
||||||
.map<Future<List<YokutangoEntry>>>(
|
|
||||||
(String t) => rootBundle
|
|
||||||
.loadString(t)
|
|
||||||
.then<List<YokutangoEntry>>((s) => jsonDecode(s)
|
|
||||||
.map<YokutangoEntry>(
|
|
||||||
(e) => YokutangoEntry.fromJson(e))
|
|
||||||
.toList()),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureBuilder(
|
|
||||||
future: tangocardFilePaths,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.hasError) {
|
|
||||||
debugPrint(snapshot.error.toString());
|
|
||||||
return const ErrorScreen();
|
|
||||||
} else if (!snapshot.hasData) {
|
|
||||||
return const LoadingScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ListView(
|
|
||||||
children: (snapshot.data as Map<File, List<YokutangoEntry>>)
|
|
||||||
.entries
|
|
||||||
.map(
|
|
||||||
(e) => ListTile(
|
|
||||||
title: Text(
|
|
||||||
"${e.key.uri.pathSegments.last} - ${e.value.length} cards"),
|
|
||||||
onTap: () => Navigator.pushNamed(context, '/tangolist',
|
|
||||||
arguments: e.key),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,23 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:tangocard_reader/models/router_args.dart';
|
|
||||||
import 'package:tangocard_reader/models/yokutango_entry.dart';
|
|
||||||
import 'package:tangocard_reader/screens/error.dart';
|
|
||||||
import 'package:tangocard_reader/screens/loading.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:tangocard_reader/models/data_entry.dart';
|
||||||
|
import 'package:tangocard_reader/models/router_args.dart';
|
||||||
|
import 'package:tangocard_reader/screens/misc/error.dart';
|
||||||
|
import 'package:tangocard_reader/screens/misc/loading.dart';
|
||||||
|
|
||||||
class TangoList extends StatelessWidget {
|
class KanjiList extends StatelessWidget {
|
||||||
final File file;
|
final File file;
|
||||||
|
|
||||||
const TangoList({
|
const KanjiList({
|
||||||
required this.file,
|
|
||||||
Key? key,
|
Key? key,
|
||||||
|
required this.file,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) => Scaffold(
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(file.uri.pathSegments.last),
|
title: Text(file.uri.pathSegments.last),
|
||||||
),
|
),
|
||||||
|
@ -33,7 +32,7 @@ class TangoList extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
final entries = (jsonSnapshot.data as List)
|
final entries = (jsonSnapshot.data as List)
|
||||||
.map((e) => YokutangoEntry.fromJson(e))
|
.map((e) => KanjiEntry.fromJson(e))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
return ListView(
|
return ListView(
|
||||||
|
@ -44,7 +43,7 @@ class TangoList extends StatelessWidget {
|
||||||
i,
|
i,
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(e.toString()),
|
title: Text(e.toString()),
|
||||||
onTap: () => Navigator.pushNamed(context, '/benkyou',
|
onTap: () => Navigator.pushNamed(context, '/benkyou/kanji',
|
||||||
arguments: BenkyouArgs(cards: entries, index: i)),
|
arguments: BenkyouArgs(cards: entries, index: i)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -53,7 +52,7 @@ class TangoList extends StatelessWidget {
|
||||||
.toList(),
|
.toList(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:tangocard_reader/models/data_entry.dart';
|
||||||
|
import 'package:tangocard_reader/models/router_args.dart';
|
||||||
|
import 'package:tangocard_reader/screens/misc/error.dart';
|
||||||
|
import 'package:tangocard_reader/screens/misc/loading.dart';
|
||||||
|
|
||||||
|
class TangoList extends StatelessWidget {
|
||||||
|
final File file;
|
||||||
|
|
||||||
|
const TangoList({
|
||||||
|
required this.file,
|
||||||
|
Key? key,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(file.uri.pathSegments.last),
|
||||||
|
),
|
||||||
|
body: FutureBuilder(
|
||||||
|
future:
|
||||||
|
rootBundle.loadString(file.path).then((data) => jsonDecode(data)),
|
||||||
|
builder: (context, jsonSnapshot) {
|
||||||
|
if (jsonSnapshot.hasError) {
|
||||||
|
return const ErrorScreen();
|
||||||
|
} else if (!jsonSnapshot.hasData) {
|
||||||
|
return const LoadingScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
final entries = (jsonSnapshot.data as List)
|
||||||
|
.map((e) => YokutangoEntry.fromJson(e))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
return ListView(
|
||||||
|
children: entries
|
||||||
|
.asMap()
|
||||||
|
.map(
|
||||||
|
(i, e) => MapEntry(
|
||||||
|
i,
|
||||||
|
ListTile(
|
||||||
|
title: Text(e.toString()),
|
||||||
|
onTap: () => Navigator.pushNamed(
|
||||||
|
context,
|
||||||
|
'/benkyou/tango',
|
||||||
|
arguments: BenkyouArgs(cards: entries, index: i),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.values
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tangocard_reader/screens/misc/error.dart';
|
||||||
|
import 'package:tangocard_reader/screens/misc/loading.dart';
|
||||||
|
|
||||||
|
class TangoSetList extends StatelessWidget {
|
||||||
|
final String route;
|
||||||
|
final Future<Map<File, List>> files;
|
||||||
|
|
||||||
|
const TangoSetList({
|
||||||
|
Key? key,
|
||||||
|
required this.route,
|
||||||
|
required this.files,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => FutureBuilder(
|
||||||
|
future: files,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasError) {
|
||||||
|
debugPrint(snapshot.error.toString());
|
||||||
|
return const ErrorScreen();
|
||||||
|
} else if (!snapshot.hasData) {
|
||||||
|
return const LoadingScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ListView(
|
||||||
|
children: (snapshot.data as Map<File, List>)
|
||||||
|
.entries
|
||||||
|
.map(
|
||||||
|
(e) => ListTile(
|
||||||
|
title: Text(
|
||||||
|
"${e.key.uri.pathSegments.last} - ${e.value.length} cards"),
|
||||||
|
onTap: () => Navigator.pushNamed(
|
||||||
|
context,
|
||||||
|
route,
|
||||||
|
arguments: e.key,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:tangocard_reader/components/flashcard.dart';
|
import 'package:tangocard_reader/components/flashcard.dart';
|
||||||
import 'package:tangocard_reader/models/yokutango_entry.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:tangocard_reader/models/data_entry.dart';
|
||||||
|
|
||||||
class FlashcardView extends StatefulWidget {
|
class FlashcardView extends StatefulWidget {
|
||||||
final List<YokutangoEntry> cards;
|
final List<YokutangoEntry> cards;
|
|
@ -0,0 +1,50 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:tangocard_reader/models/data_entry.dart';
|
||||||
|
|
||||||
|
// TODO: merge
|
||||||
|
|
||||||
|
Future<Map<File, List<YokutangoEntry>>> get tangocardFilePaths => rootBundle
|
||||||
|
.loadString('AssetManifest.json')
|
||||||
|
.then(
|
||||||
|
(json) => jsonDecode(json)
|
||||||
|
.keys
|
||||||
|
.where((String key) =>
|
||||||
|
key.contains('yokutango/json/') && key.contains('.json'))
|
||||||
|
.toList(),
|
||||||
|
)
|
||||||
|
.then(
|
||||||
|
(l) async => Map.fromIterables(
|
||||||
|
l.map<File>((f) => File(f)),
|
||||||
|
await Future.wait<List<YokutangoEntry>>(
|
||||||
|
l.map<Future<List<YokutangoEntry>>>(
|
||||||
|
(String t) => rootBundle.loadString(t).then<List<YokutangoEntry>>(
|
||||||
|
(s) => jsonDecode(s)
|
||||||
|
.map<YokutangoEntry>((e) => YokutangoEntry.fromJson(e))
|
||||||
|
.toList()),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Future<Map<File, List<KanjiEntry>>> get kanjicardFilePaths => rootBundle
|
||||||
|
.loadString('AssetManifest.json')
|
||||||
|
.then(
|
||||||
|
(json) => jsonDecode(json)
|
||||||
|
.keys
|
||||||
|
.where((String key) =>
|
||||||
|
key.contains(RegExp(r'yokutango/kanji/kanji_\d+.json')))
|
||||||
|
.toList(),
|
||||||
|
)
|
||||||
|
.then(
|
||||||
|
(l) async => Map.fromIterables(
|
||||||
|
l.map<File>((f) => File(f)),
|
||||||
|
await Future.wait<List<KanjiEntry>>(l.map<Future<List<KanjiEntry>>>(
|
||||||
|
(String t) => rootBundle.loadString(t).then<List<KanjiEntry>>((s) =>
|
||||||
|
jsonDecode(s)
|
||||||
|
.map<KanjiEntry>((e) => KanjiEntry.fromJson(e))
|
||||||
|
.toList()),
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
);
|
|
@ -176,7 +176,7 @@ packages:
|
||||||
name: vector_math
|
name: vector_math
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.12.0 <3.0.0"
|
dart: ">=2.14.0 <3.0.0"
|
||||||
flutter: ">=1.16.0"
|
flutter: ">=1.16.0"
|
||||||
|
|
Loading…
Reference in New Issue