diff --git a/CHANGELOG.md b/CHANGELOG.md index c162cf22..54471d28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 1.2.3 (Narcg 2, 2021) + +* Add a backend on default +* Fix different app bars +* Fix servers offline issues +* Add changelog to settings + ## 1.2.2 (February 24, 2021) * Fix responsive rebuild issues diff --git a/README.md b/README.md index e5008dc2..9cfbf2cc 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ > A free, opensource, serverless learning platform. A linwood project. +![Play store badge](https://img.shields.io/endpoint?color=green&style=for-the-badge&url=https%3A%2F%2Fplayshields.herokuapp.com%2Fplay%3Fi%3Dcom.github.linwoodcloud.dev_doctor%26l%3DPlay%2520Store%26m%3D%24version) +[![GitHub License badge](https://img.shields.io/github/license/LinwoodCloud/dev_doctor?style=for-the-badge)](https://github.com/LinwoodCloud/dev_doctor/blob/main/LICENSE) +[![Discord badge](https://img.shields.io/discord/735424757142519848?style=for-the-badge)](https://discord.linwood.tk) + ## Introduction ### Learn everything @@ -26,6 +30,8 @@ Click [here](https://dev-doctor.cf) and try it. You have nothing to lose! #### Stores * Play Store: +* SkyDroid: +* FDroid: ### iOS diff --git a/android/app/build.gradle b/android/app/build.gradle index 2ffe8278..2b76745b 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -42,6 +42,7 @@ android { targetSdkVersion 30 versionCode flutterVersionCode.toInteger() versionName flutterVersionName + multiDexEnabled true } signingConfigs { release { @@ -68,6 +69,8 @@ flutter { } dependencies { + def multidex_version = "2.0.1" + implementation "androidx.multidex:multidex:$multidex_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'com.google.android.material:material:1.3.0' } diff --git a/android/build.gradle b/android/build.gradle index c505a863..2536f19c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' + classpath 'com.android.tools.build:gradle:4.1.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index bc6a58af..442d9132 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 08:50:38 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip diff --git a/fastlane/metadata/android/en-US/changelogs/7.txt b/fastlane/metadata/android/en-US/changelogs/7.txt new file mode 100644 index 00000000..e5ea2fb1 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/7.txt @@ -0,0 +1,4 @@ +Add a backend on default +Fix different app bars +Fix servers offline issues +Add changelog to settings \ No newline at end of file diff --git a/lib/backends/home.dart b/lib/backends/home.dart index 396831c6..11a64465 100644 --- a/lib/backends/home.dart +++ b/lib/backends/home.dart @@ -2,6 +2,7 @@ import 'dart:math'; import 'package:dev_doctor/models/collection.dart'; import 'package:dev_doctor/models/server.dart'; +import 'package:dev_doctor/widgets/appbar.dart'; import 'package:dev_doctor/widgets/image.dart'; import 'package:flutter/material.dart'; import 'package:easy_localization/easy_localization.dart'; @@ -173,7 +174,7 @@ class _BackendsPageState extends State with TickerProviderStateMix @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text("backends.title").tr(), actions: [ + appBar: MyAppBar(title: "backends.title".tr(), actions: [ IconButton( icon: Icon(Icons.search), onPressed: () { diff --git a/lib/backends/user.dart b/lib/backends/user.dart index 9846b01b..27b1d734 100644 --- a/lib/backends/user.dart +++ b/lib/backends/user.dart @@ -1,5 +1,6 @@ import 'package:dev_doctor/models/collection.dart'; import 'package:dev_doctor/models/server.dart'; +import 'package:dev_doctor/widgets/appbar.dart'; import 'package:dev_doctor/widgets/image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_modular/flutter_modular.dart'; @@ -36,10 +37,8 @@ class BackendUserPage extends StatelessWidget { Widget _buildView(BackendUser backendUser) { var entries = backendUser.buildEntries(); - print(entries[0]); - print(entries.length); return Scaffold( - appBar: AppBar(title: Text(backendUser.name)), + appBar: MyAppBar(title: backendUser.name), body: Scrollbar( child: SingleChildScrollView( child: Wrap( diff --git a/lib/courses/home.dart b/lib/courses/home.dart index be302970..3eaf45a3 100644 --- a/lib/courses/home.dart +++ b/lib/courses/home.dart @@ -2,6 +2,7 @@ import 'dart:math'; import 'package:dev_doctor/models/course.dart'; import 'package:dev_doctor/models/server.dart'; +import 'package:dev_doctor/widgets/appbar.dart'; import 'package:dev_doctor/widgets/image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_modular/flutter_modular.dart'; @@ -115,7 +116,7 @@ class _CoursesPageState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: Text("courses.title").tr(), actions: [ + appBar: MyAppBar(title: "courses.title".tr(), actions: [ IconButton( icon: Icon(Icons.search_outlined), onPressed: () { diff --git a/lib/courses/part/layout.dart b/lib/courses/part/layout.dart index ce3e4903..063b044d 100644 --- a/lib/courses/part/layout.dart +++ b/lib/courses/part/layout.dart @@ -3,6 +3,7 @@ import 'package:dev_doctor/models/items/quiz.dart'; import 'package:dev_doctor/models/items/text.dart'; import 'package:dev_doctor/models/items/video.dart'; import 'package:dev_doctor/models/part.dart'; +import 'package:dev_doctor/widgets/appbar.dart'; import 'package:flutter/material.dart'; import 'package:flutter_modular/flutter_modular.dart'; @@ -55,8 +56,8 @@ class _PartItemLayoutState extends State { bloc?.fetch(serverId: serverId, courseId: courseId, partId: index); }, ), - appBar: AppBar( - title: Text(snapshot.data.name), + appBar: MyAppBar( + title: snapshot.data.name, bottom: TabBar( isScrollable: true, onTap: (index) => Modular.to.pushReplacementNamed( diff --git a/lib/loader.dart b/lib/loader.dart index ed90b6fc..48bfd4e7 100644 --- a/lib/loader.dart +++ b/lib/loader.dart @@ -6,11 +6,11 @@ import 'yaml.dart'; Future> loadFile(String path, {String type}) async { try { - var result = await loadJsonFile(path); + var result = await loadJsonFile(path) ?? {}; if (type == null) result['type'] = 'json'; return result; } catch (e) { - var result = await loadYamlFile(path); + var result = await loadYamlFile(path) ?? {}; if (type == null) result['type'] = 'yml'; return result; } @@ -22,6 +22,12 @@ Future> loadJsonFile(String path) async { } Future> loadYamlFile(String path) async { - var response = await http.get(Uri.parse(path + ".yml")); - return yamlMapToJson(loadYaml(utf8.decode(response.bodyBytes))); + try { + var response = await http.get(Uri.parse(path + ".yml")); + return yamlMapToJson(loadYaml(utf8.decode(response.bodyBytes))); + } catch (e) { + print(e); + } + + return null; } diff --git a/lib/main.dart b/lib/main.dart index 02ee9971..044632c5 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -11,9 +11,9 @@ void main() async { await Hive.initFlutter(); await Hive.openBox('settings'); await Hive.openBox('appearance'); - /*var _serversBox = */ await Hive.openBox('servers'); + var _serversBox = await Hive.openBox('servers'); var _collectionsBox = await Hive.openBox('collections'); if (_collectionsBox.isEmpty) await _collectionsBox.add('https://collection.dev-doctor.cf'); - // if (_serversBox.isEmpty) await _serversBox.add('https://backend.dev-doctor.cf'); + if (_serversBox.isEmpty) await _serversBox.add('https://backend.dev-doctor.cf'); runApp(ModularApp(module: AppModule(), child: AppWidget())); } diff --git a/lib/models/collection.dart b/lib/models/collection.dart index 3dfe28d1..a83599f2 100644 --- a/lib/models/collection.dart +++ b/lib/models/collection.dart @@ -29,7 +29,7 @@ class BackendCollection { var current = _box.values.toList().indexOf(url); if (current != -1) index = _box.keyAt(current); } else if (url == null) url = _box.get(index); - data = await loadFile("$url/config"); + data = await loadFile("$url/config") ?? {}; } catch (e) { print(e); } diff --git a/lib/models/server.dart b/lib/models/server.dart index 7532a65b..11b7ebb6 100644 --- a/lib/models/server.dart +++ b/lib/models/server.dart @@ -68,16 +68,17 @@ class CoursesServer { Future toggle() => added ? remove() : add(); static Future fetch({String url, int index, BackendEntry entry}) async { - var data = Map(); + var data = {}; try { if (index == null) { var current = _box.values.toList().indexOf(url); if (current != -1) index = _box.keyAt(current); } else if (url == null) url = Hive.box('servers').get(index); - data = await loadFile("$url/config"); + data = await loadFile("$url/config") ?? {}; } catch (e) { print(e); } + data['courses'] = data['courses'] ?? []; data['entry'] = entry; data['url'] = url; data['index'] = index; diff --git a/lib/settings/home.dart b/lib/settings/home.dart index 2c492c82..829115eb 100644 --- a/lib/settings/home.dart +++ b/lib/settings/home.dart @@ -85,6 +85,11 @@ class SettingsList extends StatelessWidget { leading: Icon(Icons.code_outlined), title: Text("settings.code").tr(), onTap: () => launch("https://github.com/LinwoodCloud/dev-doctor")), + ListTile( + leading: Icon(Icons.history_outlined), + title: Text("settings.changelog").tr(), + onTap: () => + launch("https://github.com/LinwoodCloud/dev_doctor/blob/main/CHANGELOG.md")), ListTile( leading: Icon(Icons.privacy_tip_outlined), title: Text("settings.privacypolicy").tr(), diff --git a/lib/settings/servers.dart b/lib/settings/servers.dart index 02fb478c..d197c227 100644 --- a/lib/settings/servers.dart +++ b/lib/settings/servers.dart @@ -20,6 +20,16 @@ class _ServersSettingsPageState extends State { super.initState(); } + Future> _buildFuture() async { + var urls = _serversBox.values.toList().asMap(); + var servers = []; + for (var key in urls.keys) { + var value = urls[key]; + servers.add(await CoursesServer.fetch(url: value, index: key)); + } + return servers; + } + @override Widget build(BuildContext context) { return Scaffold( @@ -27,19 +37,15 @@ class _ServersSettingsPageState extends State { body: SettingsLayout( child: ValueListenableBuilder( valueListenable: _serversBox.listenable(), - builder: (context, Box box, _) => FutureBuilder( - future: Future.wait(_serversBox.values - .toList() - .asMap() - .map((index, e) => MapEntry(index, CoursesServer.fetch(url: e, index: index))) - .values), + builder: (context, Box box, _) => FutureBuilder>( + future: _buildFuture(), builder: (context, snapshot) { switch (snapshot.connectionState) { case ConnectionState.waiting: return Center(child: CircularProgressIndicator()); default: if (snapshot.hasError) return Text('Error: ${snapshot.error}'); - var data = snapshot.data as List; + var data = snapshot.data; return Scrollbar( child: ListView.builder( itemCount: box.length, diff --git a/lib/widgets/appbar.dart b/lib/widgets/appbar.dart index c448c0f2..d16f5d87 100644 --- a/lib/widgets/appbar.dart +++ b/lib/widgets/appbar.dart @@ -6,7 +6,9 @@ class MyAppBar extends StatelessWidget with PreferredSizeWidget { final Size preferredSize; final List actions; - MyAppBar({this.title, this.actions, Key key}) + final PreferredSizeWidget bottom; + + MyAppBar({this.title, this.actions, Key key, this.bottom}) : preferredSize = Size.fromHeight(50.0), super(key: key); @@ -15,6 +17,7 @@ class MyAppBar extends StatelessWidget with PreferredSizeWidget { return AppBar( elevation: 5.0, title: Text(title), + bottom: bottom, actions: actions, //actions: [IconButton(icon: Icon(Icons.settings_outlined), onPressed: () {})], automaticallyImplyLeading: true, diff --git a/pubspec.lock b/pubspec.lock index e6bd083c..c8b4b281 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -162,13 +162,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.5" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" dart_style: dependency: transitive description: @@ -288,7 +281,7 @@ packages: name: flutter_svg url: "https://pub.dartlang.org" source: hosted - version: "0.20.0-nullsafety.3" + version: "0.21.0-nullsafety.0" flutter_test: dependency: "direct dev" description: flutter @@ -378,7 +371,7 @@ packages: name: io url: "https://pub.dartlang.org" source: hosted - version: "0.3.4" + version: "0.3.5" js: dependency: transitive description: @@ -553,7 +546,7 @@ packages: name: rxdart url: "https://pub.dartlang.org" source: hosted - version: "0.26.0-nullsafety.1" + version: "0.26.0" shared_preferences: dependency: transitive description: @@ -712,7 +705,7 @@ packages: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "6.0.0" + version: "6.0.1" url_launcher_linux: dependency: transitive description: @@ -817,7 +810,7 @@ packages: name: yaml url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.1.0" sdks: dart: ">=2.12.0-259.9.beta <3.0.0" flutter: ">=1.24.0-7.0" diff --git a/pubspec.yaml b/pubspec.yaml index 4e9a2204..f79a1c80 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: '1.2.2+6' +version: '1.2.3+7' environment: sdk: ">=2.7.0 <3.0.0" @@ -27,13 +27,13 @@ dependencies: enum_to_string: ^2.0.0-nullsafety.1 http: ^0.13.0 hive: ^1.4.4+1 - rxdart: ^0.26.0-nullsafety.1 + rxdart: ^0.26.0 hive_flutter: ^0.3.1 flutter_modular: ^3.0.0-nullsafety.45 url_launcher: ^6.0.0-nullsafety.7 flutter_markdown: ^0.5.2 #universal_html: ^1.2.4 - flutter_svg: ^0.20.0-nullsafety.3 + flutter_svg: ^0.21.0-nullsafety.0 flutter_inappwebview: ^4.0.0+4 xml: ^5.0.0-nullsafety.1 flutter_localized_locales: ^2.0.1 @@ -41,8 +41,8 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.2 - yaml: ^3.0.0 + # cupertino_icons: ^1.0.2 + yaml: ^3.1.0 flutter_icons: android: true ios: true diff --git a/translations/de.json b/translations/de.json index 474ce698..97b603b0 100644 --- a/translations/de.json +++ b/translations/de.json @@ -55,6 +55,7 @@ "information": "Informationen", "title": "Einstellungen", "privacypolicy": "Datenschutzerklärung", + "changelog":"Änderungsliste", "home": { "title": "Start", "username": "Benutzername" diff --git a/translations/en.json b/translations/en.json index 0ba99f38..dbe427a6 100644 --- a/translations/en.json +++ b/translations/en.json @@ -55,6 +55,7 @@ "information": "Information", "title": "Settings", "privacypolicy": "Privacy Policy", + "changelog":"Changelog", "home": { "title": "Home", "username": "Username"