.
This commit is contained in:
+16
-16
@@ -5,23 +5,27 @@
|
|||||||
*.swp
|
*.swp
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.atom/
|
.atom/
|
||||||
|
.build/
|
||||||
.buildlog/
|
.buildlog/
|
||||||
.history
|
.history
|
||||||
.svn/
|
.svn/
|
||||||
|
.swiftpm/
|
||||||
migrate_working_dir/
|
migrate_working_dir/
|
||||||
.dart_tool/
|
*.metadeta
|
||||||
macos/
|
*main_sub_test*
|
||||||
test/
|
*main_test*
|
||||||
web/
|
|
||||||
linux/
|
|
||||||
windows/
|
|
||||||
.rmv/
|
|
||||||
|
|
||||||
# IntelliJ related
|
# IntelliJ related
|
||||||
*.iml
|
*.iml
|
||||||
*.ipr
|
*.ipr
|
||||||
*.iws
|
*.iws
|
||||||
.idea/
|
.idea/
|
||||||
|
*.gitignore
|
||||||
|
*ios
|
||||||
|
*android
|
||||||
|
*.vscode
|
||||||
|
*pubspec.lock
|
||||||
|
*test/
|
||||||
|
|
||||||
# The .vscode folder contains launch configuration and tasks you configure in
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
# VS Code which you may wish to be included in version control, so this line
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
@@ -29,11 +33,8 @@ windows/
|
|||||||
#.vscode/
|
#.vscode/
|
||||||
|
|
||||||
# Flutter/Dart/Pub related
|
# Flutter/Dart/Pub related
|
||||||
# **/doc/api/
|
**/doc/api/
|
||||||
# **/ios/Flutter/.last_build_id
|
**/ios/Flutter/.last_build_id
|
||||||
|
|
||||||
*/doc/api/
|
|
||||||
ios/
|
|
||||||
.dart_tool/
|
.dart_tool/
|
||||||
.flutter-plugins
|
.flutter-plugins
|
||||||
.flutter-plugins-dependencies
|
.flutter-plugins-dependencies
|
||||||
@@ -48,7 +49,6 @@ app.*.symbols
|
|||||||
app.*.map.json
|
app.*.map.json
|
||||||
|
|
||||||
# Android Studio will place build artifacts here
|
# Android Studio will place build artifacts here
|
||||||
# android/app/debug
|
/android/app/debug
|
||||||
# android/app/profile
|
/android/app/profile
|
||||||
# android/app/release
|
/android/app/release
|
||||||
android/
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
# This file should be version controlled and should not be manually edited.
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
version:
|
version:
|
||||||
revision: "761747bfc538b5af34aa0d3fac380f1bc331ec49"
|
revision: "17025dd88227cd9532c33fa78f5250d548d87e9a"
|
||||||
channel: "stable"
|
channel: "stable"
|
||||||
|
|
||||||
project_type: app
|
project_type: app
|
||||||
@@ -13,26 +13,26 @@ project_type: app
|
|||||||
migration:
|
migration:
|
||||||
platforms:
|
platforms:
|
||||||
- platform: root
|
- platform: root
|
||||||
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||||
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||||
- platform: android
|
- platform: android
|
||||||
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||||
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||||
- platform: ios
|
- platform: ios
|
||||||
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||||
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||||
- platform: linux
|
- platform: linux
|
||||||
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||||
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||||
- platform: macos
|
- platform: macos
|
||||||
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||||
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||||
- platform: web
|
- platform: web
|
||||||
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||||
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||||
- platform: windows
|
- platform: windows
|
||||||
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||||
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a
|
||||||
|
|
||||||
# User provided section
|
# User provided section
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
@@ -0,0 +1,3 @@
|
|||||||
|
description: This file stores settings for Dart & Flutter DevTools.
|
||||||
|
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||||
|
extensions:
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import 'package:nextcloud/nextcloud.dart';
|
|
||||||
import 'package:nextcloud/provisioning_api.dart';
|
|
||||||
|
|
||||||
Future<String> login(String uri, String username, String password) async {
|
|
||||||
try {
|
|
||||||
|
|
||||||
final client = NextcloudClient(
|
|
||||||
Uri.parse(uri),
|
|
||||||
loginName: username,
|
|
||||||
password: password,
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
final response =
|
|
||||||
await client.provisioningApi.users.getUser(userId: username);
|
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
|
||||||
print(response.body);
|
|
||||||
return "successful|$response.body.ocs.data.";
|
|
||||||
} else {
|
|
||||||
return "failed|$response.body.ocs.data";
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
print("");
|
|
||||||
print("$e");
|
|
||||||
print("");
|
|
||||||
return "$e";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:http/io_client.dart';
|
||||||
|
import 'package:nextcloud/nextcloud.dart';
|
||||||
|
|
||||||
|
|
||||||
|
extension NextcloudClientExtension on NextcloudClient {
|
||||||
|
//
|
||||||
|
static final userAgent = 'NextCloud App'
|
||||||
|
'(${Platform.operatingSystem}) ';
|
||||||
|
// 'Dart/${Platform.version.split(' ').first}';
|
||||||
|
|
||||||
|
//
|
||||||
|
static IOClient newHttpClient() => IOClient(
|
||||||
|
HttpClient()..userAgent = userAgent,
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:nextcloud/core.dart';
|
||||||
|
import 'package:nextcloud/nextcloud.dart';
|
||||||
|
import 'package:nextcloudapp/app/extension.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
class SaberLoginFlow {
|
||||||
|
SaberLoginFlow.start({
|
||||||
|
required this.serverUrl,
|
||||||
|
}) {
|
||||||
|
// NcHttpOverrides.tempAcceptBadCertificateFrom(serverUrl);
|
||||||
|
unawaited(_run());
|
||||||
|
}
|
||||||
|
|
||||||
|
final Uri serverUrl;
|
||||||
|
|
||||||
|
final log = Logger('SaberLoginFlow');
|
||||||
|
Timer? _pollTimer;
|
||||||
|
|
||||||
|
final completer = Completer<LoginFlowV2Credentials>();
|
||||||
|
late final future = completer.future;
|
||||||
|
|
||||||
|
LoginFlowV2? init;
|
||||||
|
|
||||||
|
Future<void> openLoginUrl() async {
|
||||||
|
final init = this.init;
|
||||||
|
if (init == null) return;
|
||||||
|
|
||||||
|
if (Platform.isMacOS || Platform.isIOS || Platform.isAndroid) {
|
||||||
|
// Use FlutterWebAuth2 which returns to Saber when authenticated
|
||||||
|
log.info('Opening login link in-app: ${init.login}');
|
||||||
|
await FlutterWebAuth2.authenticate(
|
||||||
|
url: init.login,
|
||||||
|
callbackUrlScheme: 'nc',
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Use url_launcher to open the link in the default browser
|
||||||
|
log.info('Opening login link in browser: ${init.login}');
|
||||||
|
final loginLink = Uri.parse(init.login);
|
||||||
|
await launchUrl(loginLink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _run() async {
|
||||||
|
_catchHttpError(() async {
|
||||||
|
final client = NextcloudClient(serverUrl,
|
||||||
|
httpClient: NextcloudClientExtension.newHttpClient());
|
||||||
|
final flowClient = client.core.clientFlowLoginV2;
|
||||||
|
init = await flowClient.init().then((response) => response.body);
|
||||||
|
log.info('init: $init');
|
||||||
|
|
||||||
|
openLoginUrl();
|
||||||
|
|
||||||
|
_pollTimer?.cancel();
|
||||||
|
_pollTimer = Timer.periodic(
|
||||||
|
const Duration(seconds: 1),
|
||||||
|
(_) => _catch404Error(() async {
|
||||||
|
// Throws 404 if not logged in yet
|
||||||
|
final poll = await flowClient.poll(
|
||||||
|
$body: ClientFlowLoginV2PollRequestApplicationJson(
|
||||||
|
(b) => b..token = init!.poll.token,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
_pollTimer?.cancel();
|
||||||
|
if (!completer.isCompleted) completer.complete(poll.body);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<T?> _catchHttpError<T>(Future<T> Function() fn) async {
|
||||||
|
try {
|
||||||
|
return await fn();
|
||||||
|
} on http.ClientException catch (error, stackTrace) {
|
||||||
|
log.severe('Error while polling the login flow.', error, stackTrace);
|
||||||
|
if (!completer.isCompleted) completer.completeError(error, stackTrace);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<T?> _catch404Error<T>(Future<T> Function() fn) async {
|
||||||
|
try {
|
||||||
|
return await fn();
|
||||||
|
} on DynamiteStatusCodeException catch (error) {
|
||||||
|
if (error.statusCode != 404) rethrow;
|
||||||
|
|
||||||
|
log.fine('Login flow not found or completed yet, will repoll');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
_pollTimer?.cancel();
|
||||||
|
if (!completer.isCompleted) {
|
||||||
|
completer.completeError(TimeoutException('Login flow was disposed'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:nextcloudapp/components/nextcloud_routes.dart';
|
||||||
|
import 'package:nextcloudapp/service/navigation_service.dart';
|
||||||
|
|
||||||
|
class NextcloudApp extends StatelessWidget {
|
||||||
|
NextcloudApp({
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final NextcloudAppRoutes _nextcloudAppRoutes = NextcloudAppRoutes.instance;
|
||||||
|
final NavigationService _navigationService = NavigationService.instance;
|
||||||
|
|
||||||
|
// This widget is the root of your application.
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
|
debugShowCheckedModeBanner: false,
|
||||||
|
title: 'Nextcloud App',
|
||||||
|
navigatorKey: _navigationService.navigatorKey,
|
||||||
|
theme: ThemeData(
|
||||||
|
primaryColor: Color.fromARGB(255, 152, 120, 57),
|
||||||
|
scaffoldBackgroundColor: Colors.white,
|
||||||
|
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
elevation: 0,
|
||||||
|
foregroundColor: Colors.white,
|
||||||
|
backgroundColor: Color.fromARGB(255, 152, 120, 57),
|
||||||
|
shape: const StadiumBorder(),
|
||||||
|
maximumSize: const Size(double.infinity, 56),
|
||||||
|
minimumSize: const Size(double.infinity, 56),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// inputDecorationTheme: const InputDecorationTheme(
|
||||||
|
// filled: true,
|
||||||
|
// fillColor: primaryLightColor,
|
||||||
|
// iconColor: primaryColor,
|
||||||
|
// prefixIconColor: primaryColor,
|
||||||
|
// contentPadding: EdgeInsets.symmetric(
|
||||||
|
// horizontal: defaultPadding, vertical: defaultPadding),
|
||||||
|
// border: OutlineInputBorder(
|
||||||
|
// borderRadius: BorderRadius.all(Radius.circular(30)),
|
||||||
|
// borderSide: BorderSide.none,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
fontFamily: 'Poppins',
|
||||||
|
),
|
||||||
|
routes: _nextcloudAppRoutes.routes,
|
||||||
|
initialRoute: "login",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
// import 'package:nextcloud/nextcloud.dart';
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
// import 'package:http/http.dart' as http;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const primaryColor = Color.fromARGB(255, 26, 26, 74);
|
|
||||||
const primaryLightColor = Color.fromARGB(150, 238, 224, 173);
|
|
||||||
const double defaultPadding = 15.0;
|
|
||||||
const timeout = 3;
|
|
||||||
// var client = http.Client();
|
|
||||||
// var client = NextcloudClient()
|
|
||||||
|
|
||||||
|
|
||||||
setSharedPref(String key, var value) async {
|
|
||||||
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
|
|
||||||
|
|
||||||
switch (value.runtimeType.toString()) {
|
|
||||||
case 'String':
|
|
||||||
sharedPreferences.setString(key, value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'double':
|
|
||||||
sharedPreferences.setDouble(key, value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'int':
|
|
||||||
sharedPreferences.setInt(key, value);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'bool':
|
|
||||||
sharedPreferences.setBool(key, value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getSharedPref(var key, var type) async {
|
|
||||||
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case 'String':
|
|
||||||
return sharedPreferences.getString(key);
|
|
||||||
|
|
||||||
case 'double':
|
|
||||||
return sharedPreferences.getDouble(key);
|
|
||||||
|
|
||||||
case 'int':
|
|
||||||
return sharedPreferences.getInt(key);
|
|
||||||
|
|
||||||
case 'bool':
|
|
||||||
return sharedPreferences.getBool(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
class FileSize {
|
||||||
|
static FileSize instance = FileSize();
|
||||||
|
|
||||||
|
String getFileSizeString({required int bytes, int decimals = 0}) {
|
||||||
|
const suffixes = ["Bytes", "KB", "MB", "GB", "TB"];
|
||||||
|
if (bytes == 0) return '0 ${suffixes[0]}';
|
||||||
|
|
||||||
|
var i = (log(bytes) / log(1024)).floor();
|
||||||
|
return "${(bytes / pow(1024, i)).toStringAsFixed(
|
||||||
|
i == 0 ? 0 : decimals,
|
||||||
|
)} ${suffixes[i]}";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class MimetypeIcon {
|
||||||
|
static MimetypeIcon instance = MimetypeIcon();
|
||||||
|
|
||||||
|
IconData getIconForMimeType(String mimeType) {
|
||||||
|
if (mimeType.startsWith('image/')) {
|
||||||
|
return Icons.image;
|
||||||
|
} else if (mimeType.startsWith('video/')) {
|
||||||
|
return Icons.video_file;
|
||||||
|
} else if (mimeType.startsWith('audio/')) {
|
||||||
|
return Icons.audiotrack;
|
||||||
|
} else if (mimeType == 'application/pdf') {
|
||||||
|
return Icons.picture_as_pdf;
|
||||||
|
} else if (mimeType.startsWith('text/')) {
|
||||||
|
return Icons.text_snippet;
|
||||||
|
} else if (mimeType.contains("application/octet-stream")) {
|
||||||
|
return Icons.disc_full_rounded;
|
||||||
|
} else if (mimeType.contains("application/zip")) {
|
||||||
|
return Icons.folder_zip;
|
||||||
|
} else {
|
||||||
|
return Icons.folder; // Default icon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:nextcloudapp/screens/login_screen.dart';
|
||||||
|
import 'package:nextcloudapp/screens/home_screen.dart';
|
||||||
|
|
||||||
|
class NextcloudAppRoutes {
|
||||||
|
//
|
||||||
|
static NextcloudAppRoutes instance = NextcloudAppRoutes();
|
||||||
|
|
||||||
|
Map<String, WidgetBuilder> get routes => {
|
||||||
|
"login": (BuildContext _context) => LoginScreen(),
|
||||||
|
"home": (BuildContext _context) => HomeSceen(),
|
||||||
|
};
|
||||||
|
}
|
||||||
+6
-43
@@ -1,48 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:nextcloudapp/components/default_values.dart';
|
import 'package:nextcloudapp/app/nextcloud_app.dart';
|
||||||
import 'package:nextcloudapp/screens/login_screen.dart';
|
|
||||||
|
|
||||||
void main() => runApp(
|
void main() {
|
||||||
const MyApp(),
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
runApp(
|
||||||
|
NextcloudApp(),
|
||||||
);
|
);
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
|
||||||
const MyApp({super.key});
|
|
||||||
|
|
||||||
// This widget is the root of your application.
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return MaterialApp(
|
|
||||||
debugShowCheckedModeBanner: false,
|
|
||||||
title: 'Nextcloud',
|
|
||||||
theme: ThemeData(
|
|
||||||
primaryColor: primaryColor,
|
|
||||||
scaffoldBackgroundColor: Colors.white,
|
|
||||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
elevation: 0,
|
|
||||||
foregroundColor: Colors.white,
|
|
||||||
backgroundColor: primaryColor,
|
|
||||||
shape: const StadiumBorder(),
|
|
||||||
maximumSize: const Size(double.infinity, 56),
|
|
||||||
minimumSize: const Size(double.infinity, 56),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
inputDecorationTheme: const InputDecorationTheme(
|
|
||||||
filled: true,
|
|
||||||
fillColor: primaryLightColor,
|
|
||||||
iconColor: primaryColor,
|
|
||||||
prefixIconColor: primaryColor,
|
|
||||||
contentPadding: EdgeInsets.symmetric(
|
|
||||||
horizontal: defaultPadding, vertical: defaultPadding),
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(30)),
|
|
||||||
borderSide: BorderSide.none,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
fontFamily: 'Poppins',
|
|
||||||
),
|
|
||||||
home: const LoginScreen(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import 'package:nextcloud/nextcloud.dart';
|
||||||
|
|
||||||
|
class ServerDetails {
|
||||||
|
String name;
|
||||||
|
String description;
|
||||||
|
|
||||||
|
ServerDetails({
|
||||||
|
required this.name,
|
||||||
|
required this.description,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory ServerDetails.fromTheme(Map _themeValues) {
|
||||||
|
//
|
||||||
|
DynamiteResponse icon = _themeValues['icon'];
|
||||||
|
DynamiteResponse theme = _themeValues['systemtheme'];
|
||||||
|
|
||||||
|
return ServerDetails(name: '', description: '');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import 'package:nextcloud/webdav.dart';
|
||||||
|
|
||||||
|
class Files {
|
||||||
|
String? path;
|
||||||
|
String? name;
|
||||||
|
String? resourceType;
|
||||||
|
String? contentType;
|
||||||
|
DateTime? creationDate;
|
||||||
|
DateTime? modifiedDate;
|
||||||
|
int? size;
|
||||||
|
|
||||||
|
Files({
|
||||||
|
required this.path,
|
||||||
|
required this.name,
|
||||||
|
required this.resourceType,
|
||||||
|
required this.contentType,
|
||||||
|
required this.creationDate,
|
||||||
|
required this.modifiedDate,
|
||||||
|
required this.size,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory Files.fromWebDavResponse(WebDavResponse _response) {
|
||||||
|
//
|
||||||
|
var _name;
|
||||||
|
var _resourceType;
|
||||||
|
var _size;
|
||||||
|
|
||||||
|
var _tempPath = _response.href!.split("/");
|
||||||
|
var _length = _tempPath.length;
|
||||||
|
var _collection = _response.propstats[0].prop.davResourcetype!.collection;
|
||||||
|
if (_collection == null) {
|
||||||
|
_resourceType = 'file';
|
||||||
|
_name = _tempPath[_length - 1];
|
||||||
|
_size = _response.propstats[0].prop.davGetcontentlength;
|
||||||
|
} else {
|
||||||
|
_resourceType = 'folder';
|
||||||
|
_name = _tempPath[_length - 2].contains("dav")
|
||||||
|
? ".."
|
||||||
|
: _tempPath[_length - 2];
|
||||||
|
_size = _response.propstats[0].prop.davQuotaUsedBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Files(
|
||||||
|
path: _response.href ?? '',
|
||||||
|
name: Uri.decodeFull(_name),
|
||||||
|
contentType: _response.propstats[0].prop.davGetcontenttype ?? '',
|
||||||
|
creationDate: DateTime.now(),
|
||||||
|
modifiedDate: _response.propstats[0].prop.davGetlastmodified,
|
||||||
|
size: _size,
|
||||||
|
resourceType: _resourceType,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:http/http.dart';
|
||||||
|
import 'package:nextcloud/core.dart';
|
||||||
|
import 'package:nextcloud/nextcloud.dart';
|
||||||
|
import 'package:nextcloud/provisioning_api.dart';
|
||||||
|
import 'package:nextcloud/theming.dart';
|
||||||
|
import 'package:nextcloud/webdav.dart';
|
||||||
|
import 'package:nextcloudapp/app/extension.dart';
|
||||||
|
import 'package:nextcloudapp/models/details.dart';
|
||||||
|
import 'package:nextcloudapp/models/files.dart';
|
||||||
|
|
||||||
|
import 'package:nextcloudapp/service/navigation_service.dart';
|
||||||
|
import 'package:nextcloudapp/service/snackbar_service.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
enum AuthStatus {
|
||||||
|
notAuthenticated,
|
||||||
|
authenticated,
|
||||||
|
authenticating,
|
||||||
|
userNotFound,
|
||||||
|
error,
|
||||||
|
}
|
||||||
|
|
||||||
|
class NextcloudProvider extends ChangeNotifier {
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
static NextcloudProvider instance = NextcloudProvider();
|
||||||
|
final NavigationService _navigationService = NavigationService.instance;
|
||||||
|
|
||||||
|
late NextcloudClient client;
|
||||||
|
final SharedPreferencesAsync _sharedPreferences = SharedPreferencesAsync();
|
||||||
|
// SharedPreferences? _sharedPreferences;
|
||||||
|
|
||||||
|
AuthStatus? status;
|
||||||
|
UserDetails? userDetails;
|
||||||
|
|
||||||
|
NextcloudProvider() {
|
||||||
|
// _init();
|
||||||
|
_checkLogin();
|
||||||
|
}
|
||||||
|
|
||||||
|
// void _init() async {
|
||||||
|
// _sharedPreferences = SharedPreferencesAsync();
|
||||||
|
// }
|
||||||
|
|
||||||
|
void _checkLogin() async {
|
||||||
|
await Future.delayed(Duration(milliseconds: 300));
|
||||||
|
try {
|
||||||
|
String? _appPassword = await _sharedPreferences.getString('apppassword');
|
||||||
|
print(_appPassword);
|
||||||
|
String? _uri = await _sharedPreferences.getString('uri');
|
||||||
|
if (_appPassword != null && _uri != null) {
|
||||||
|
client = NextcloudClient(
|
||||||
|
Uri.parse(_uri),
|
||||||
|
appPassword: _appPassword,
|
||||||
|
httpClient: NextcloudClientExtension.newHttpClient(),
|
||||||
|
);
|
||||||
|
|
||||||
|
var _user = await client.provisioningApi.users.getCurrentUser();
|
||||||
|
userDetails = _user.body.ocs.data;
|
||||||
|
|
||||||
|
status = AuthStatus.authenticated;
|
||||||
|
_navigationService.navigateToReplacement("home");
|
||||||
|
} else {
|
||||||
|
status = AuthStatus.notAuthenticated;
|
||||||
|
}
|
||||||
|
} on Exception catch (e) {
|
||||||
|
status = AuthStatus.notAuthenticated;
|
||||||
|
SnackBarService.instance.showSnackBarError("$e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<ServerDetails> envData() async {
|
||||||
|
Map _themeValues = {};
|
||||||
|
|
||||||
|
_themeValues['icon'] = await client.theming.icon.getFavicon();
|
||||||
|
_themeValues['systemtheme'] = await client.theming.theming.getManifest();
|
||||||
|
|
||||||
|
return ServerDetails.fromTheme(_themeValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> login(String _uri, String _username, String _password,
|
||||||
|
bool _savePassword) async {
|
||||||
|
notifyListeners();
|
||||||
|
status = AuthStatus.error;
|
||||||
|
try {
|
||||||
|
status = AuthStatus.authenticating;
|
||||||
|
client = NextcloudClient(
|
||||||
|
Uri.parse(_uri),
|
||||||
|
loginName: _username,
|
||||||
|
password: _password,
|
||||||
|
httpClient: NextcloudClientExtension.newHttpClient(),
|
||||||
|
);
|
||||||
|
var _user = await client.provisioningApi.users.getCurrentUser();
|
||||||
|
userDetails = _user.body.ocs.data;
|
||||||
|
client.core.appPassword.getAppPassword().then((_response) async {
|
||||||
|
await _sharedPreferences.setString(
|
||||||
|
'apppassword', _response.body.ocs.data.apppassword);
|
||||||
|
await _sharedPreferences.setString('uri', _uri);
|
||||||
|
await _sharedPreferences.setString('username', _username);
|
||||||
|
if (_savePassword) {
|
||||||
|
await _sharedPreferences.setString('password', _password);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
status = AuthStatus.authenticated;
|
||||||
|
SnackBarService.instance.showSnackBarSuccess('successfully logged in');
|
||||||
|
_navigationService.navigateToReplacement("home");
|
||||||
|
} on ClientException catch (e) {
|
||||||
|
SnackBarService.instance.showSnackBarError("$e");
|
||||||
|
status = AuthStatus.error;
|
||||||
|
} on Exception catch (e) {
|
||||||
|
status = AuthStatus.error;
|
||||||
|
SnackBarService.instance.showSnackBarError("$e");
|
||||||
|
}
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void logout() async {
|
||||||
|
try {
|
||||||
|
var _resp = await client.core.appPassword.deleteAppPassword();
|
||||||
|
if (_resp.statusCode == 200) {
|
||||||
|
_sharedPreferences.remove('apppassword');
|
||||||
|
SnackBarService.instance.showSnackBarSuccess("succssfully loggedout");
|
||||||
|
_navigationService.navigateToReplacement("login");
|
||||||
|
} else {
|
||||||
|
SnackBarService.instance
|
||||||
|
.showSnackBarError(_resp.body.ocs.meta.message!);
|
||||||
|
}
|
||||||
|
} on Exception catch (e) {
|
||||||
|
SnackBarService.instance.showSnackBarError("$e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<Files>> listDirectory(String _cd) async {
|
||||||
|
List<Files> _fileList = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
WebDavClient _client = client.webdav;
|
||||||
|
var _returnVal = await _client.propfind(
|
||||||
|
PathUri.parse(Uri.decodeFull(_cd)),
|
||||||
|
prop: WebDavPropWithoutValues(),
|
||||||
|
depth: WebDavDepth.one,
|
||||||
|
);
|
||||||
|
|
||||||
|
_fileList = _returnVal.responses.map((_value) {
|
||||||
|
return Files.fromWebDavResponse(_value);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
_fileList[0].name = "..";
|
||||||
|
_fileList[0].size = 0;
|
||||||
|
_fileList[0].resourceType = 'folder';
|
||||||
|
List<Files> filteredList = List.from(_fileList)..removeAt(0);
|
||||||
|
filteredList.sort((a, b) => b.resourceType!.compareTo(a.resourceType!));
|
||||||
|
filteredList.insert(0, _fileList[0]);
|
||||||
|
return filteredList;
|
||||||
|
} on Exception catch (e) {
|
||||||
|
print(e.toString());
|
||||||
|
return Future.delayed(Duration.zero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getIt() async {
|
||||||
|
Directory? storageDirectory = await getApplicationDocumentsDirectory();
|
||||||
|
String _sdPath = storageDirectory.path;
|
||||||
|
var d = Directory(_sdPath);
|
||||||
|
if (!d.existsSync()) {
|
||||||
|
d.createSync(recursive: true);
|
||||||
|
File _fileTemp = File("$_sdPath/.nomedia");
|
||||||
|
_fileTemp.writeAsString('');
|
||||||
|
}
|
||||||
|
|
||||||
|
// File temp = File('$_sdPath/temp.png');
|
||||||
|
|
||||||
|
// await _client.getFile(
|
||||||
|
// PathUri.parse("/files/${userDetails!.id}/Nextcloud.png"), temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,252 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:nextcloud/webdav.dart';
|
||||||
|
import 'package:nextcloudapp/components/file_size.dart';
|
||||||
|
import 'package:nextcloudapp/models/files.dart';
|
||||||
|
import 'package:nextcloudapp/provider/nextcloud_provider.dart';
|
||||||
|
import 'package:nextcloudapp/service/snackbar_service.dart';
|
||||||
|
import 'package:nextcloudapp/components/mime_type.dart';
|
||||||
|
import 'package:file_icon/file_icon.dart';
|
||||||
|
|
||||||
|
class HomeSceen extends StatefulWidget {
|
||||||
|
const HomeSceen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<HomeSceen> createState() => _HomeSceenState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HomeSceenState extends State<HomeSceen> {
|
||||||
|
//
|
||||||
|
var _deviceHeight;
|
||||||
|
var _deviceWidth;
|
||||||
|
var _percentage;
|
||||||
|
var _usedMemory;
|
||||||
|
var _totalMemory;
|
||||||
|
var _cwd;
|
||||||
|
|
||||||
|
List<String> _temp = [];
|
||||||
|
List<Files>? _data = [];
|
||||||
|
|
||||||
|
final MimetypeIcon _mimetypeIcon = MimetypeIcon.instance;
|
||||||
|
final FileSize _fileSize = FileSize.instance;
|
||||||
|
final NextcloudProvider _provider = NextcloudProvider.instance;
|
||||||
|
|
||||||
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
|
||||||
|
_HomeSceenState() {
|
||||||
|
_cwd = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
_deviceHeight = MediaQuery.of(context).size.height;
|
||||||
|
_deviceWidth = MediaQuery.of(context).size.width;
|
||||||
|
SnackBarService.instance.buildContext = context;
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
height: _deviceHeight * 0.10,
|
||||||
|
width: _deviceWidth * 0.20,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
image: DecorationImage(
|
||||||
|
image: AssetImage('assets/images/nextcloud_logo.png'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text("NextCloud"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
drawer: _appDrawerUI(),
|
||||||
|
body: _appBodyUI(),
|
||||||
|
floatingActionButton: _floatingButton());
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _floatingButton() {
|
||||||
|
return SpeedDial(
|
||||||
|
closeManually: true,
|
||||||
|
animatedIcon: AnimatedIcons.menu_arrow,
|
||||||
|
children: [
|
||||||
|
SpeedDialChild(
|
||||||
|
label: "File Upload",
|
||||||
|
child: Icon(Icons.upload),
|
||||||
|
),
|
||||||
|
SpeedDialChild(
|
||||||
|
label: "Folder Upload",
|
||||||
|
child: Icon(Icons.upload),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _appDrawerUI() {
|
||||||
|
_totalMemory = _provider.userDetails!.quota.total;
|
||||||
|
_usedMemory = _provider.userDetails!.quota.used;
|
||||||
|
_percentage = (_usedMemory / _totalMemory);
|
||||||
|
return NavigationDrawer(
|
||||||
|
backgroundColor: Color.fromARGB(255, 72, 160, 232),
|
||||||
|
children: [
|
||||||
|
Stack(
|
||||||
|
clipBehavior: Clip.none,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: _deviceHeight * 0.05,
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Text(_provider.userDetails!.displayName),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
_provider.logout();
|
||||||
|
},
|
||||||
|
icon: Icon(Icons.logout_sharp),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: _deviceHeight * 0.20,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Memory Usage',
|
||||||
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
LinearProgressIndicator(
|
||||||
|
value: _percentage,
|
||||||
|
backgroundColor: Colors.grey[300],
|
||||||
|
valueColor: AlwaysStoppedAnimation<Color>(
|
||||||
|
_percentage > 0.80 ? Colors.red : Colors.green,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
Text(
|
||||||
|
'${(_percentage * 100).toStringAsFixed(2)}% used',
|
||||||
|
style: TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'${_fileSize.getFileSizeString(
|
||||||
|
bytes: _usedMemory,
|
||||||
|
decimals: 1,
|
||||||
|
)} of ${_fileSize.getFileSizeString(
|
||||||
|
bytes: _totalMemory,
|
||||||
|
decimals: 1,
|
||||||
|
)}',
|
||||||
|
style: TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _appBodyUI() {
|
||||||
|
return SizedBox(
|
||||||
|
height: _deviceHeight * 0.80,
|
||||||
|
child: FutureBuilder(
|
||||||
|
future: _provider.listDirectory(_cwd),
|
||||||
|
builder: (context, _snapshot) {
|
||||||
|
_data = _snapshot.data;
|
||||||
|
if (_data != null) {
|
||||||
|
// WidgetsBinding.instance.addPostFrameCallback(
|
||||||
|
// (_) {
|
||||||
|
// if (_scrollController.hasClients) {
|
||||||
|
// _scrollController
|
||||||
|
// .jumpTo(_scrollController.position.minScrollExtent);
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
|
||||||
|
return Scrollbar(
|
||||||
|
controller: _scrollController,
|
||||||
|
child: ListView.builder(
|
||||||
|
controller: _scrollController,
|
||||||
|
itemCount: _data!.length,
|
||||||
|
itemBuilder: (BuildContext _context, int _index) {
|
||||||
|
return ListTile(
|
||||||
|
onLongPress: () {},
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
if (_data![_index].resourceType! == "folder") {
|
||||||
|
if (_index == 0) {
|
||||||
|
_temp.removeAt(_temp.length - 2);
|
||||||
|
_cwd = _temp
|
||||||
|
.join("/")
|
||||||
|
.replaceAll(webdavBase.toString(), '');
|
||||||
|
} else {
|
||||||
|
_cwd = _data![_index]
|
||||||
|
.path!
|
||||||
|
.replaceAll(webdavBase.toString(), '');
|
||||||
|
_temp = _data![_index].path!.split("/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
leading: _data![_index].resourceType! == 'folder'
|
||||||
|
? Icon(_mimetypeIcon
|
||||||
|
.getIconForMimeType(_data![_index].contentType!))
|
||||||
|
: FileIcon(
|
||||||
|
_data![_index].name!,
|
||||||
|
size: 32.0,
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
_data![_index].name!,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: TextStyle(fontSize: 15),
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
_index == 0
|
||||||
|
? ''
|
||||||
|
: DateFormat('dd MMM, yyyy hh:mm a')
|
||||||
|
.format(_data![_index].modifiedDate!),
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
trailing: Text(
|
||||||
|
_index != 0
|
||||||
|
? _fileSize.getFileSizeString(
|
||||||
|
bytes: _data![_index].size!,
|
||||||
|
decimals: 2,
|
||||||
|
)
|
||||||
|
: '',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (_snapshot.hasError) {
|
||||||
|
return Align(
|
||||||
|
child: Text("No Data"),
|
||||||
|
);
|
||||||
|
} else if (_snapshot.connectionState == ConnectionState.waiting) {
|
||||||
|
return Align(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Align(
|
||||||
|
child: Text("Undecided"),
|
||||||
|
);
|
||||||
|
;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:nextcloudapp/api/login_api.dart';
|
import 'package:nextcloudapp/provider/nextcloud_provider.dart';
|
||||||
import 'package:nextcloudapp/components/default_values.dart';
|
|
||||||
import 'package:nextcloudapp/screens/welcome_screen.dart';
|
|
||||||
import 'package:nextcloudapp/service/snackbar_service.dart';
|
import 'package:nextcloudapp/service/snackbar_service.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class LoginScreen extends StatefulWidget {
|
class LoginScreen extends StatefulWidget {
|
||||||
const LoginScreen({super.key});
|
const LoginScreen({super.key});
|
||||||
@@ -14,44 +13,55 @@ class LoginScreen extends StatefulWidget {
|
|||||||
class _LoginScreenState extends State<LoginScreen> {
|
class _LoginScreenState extends State<LoginScreen> {
|
||||||
var _deviceHeight;
|
var _deviceHeight;
|
||||||
var _deviceWidth;
|
var _deviceWidth;
|
||||||
var urlController;
|
var _url;
|
||||||
var usernameController;
|
var _username;
|
||||||
var passwordController;
|
var _password;
|
||||||
|
var enableInput = true;
|
||||||
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
var savePassword = false;
|
||||||
|
|
||||||
var checked = false;
|
|
||||||
var obscureText = true;
|
var obscureText = true;
|
||||||
|
|
||||||
|
NextcloudProvider _provider = NextcloudProvider.instance;
|
||||||
|
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
SnackBarService.instance.buildContext = context;
|
|
||||||
_deviceHeight = MediaQuery.of(context).size.height;
|
_deviceHeight = MediaQuery.of(context).size.height;
|
||||||
_deviceWidth = MediaQuery.of(context).size.width;
|
_deviceWidth = MediaQuery.of(context).size.width;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Align(
|
body: Align(
|
||||||
child: Container(
|
child: ChangeNotifierProvider<NextcloudProvider>.value(
|
||||||
height: _deviceHeight * 0.60,
|
value: _provider,
|
||||||
|
child: _loginPage(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _loginPage() {
|
||||||
|
return Builder(builder: (BuildContext _context) {
|
||||||
|
SnackBarService.instance.buildContext = _context;
|
||||||
|
_provider = Provider.of<NextcloudProvider>(_context);
|
||||||
|
return Container(
|
||||||
|
height: _deviceHeight * 0.80,
|
||||||
padding: EdgeInsets.symmetric(horizontal: _deviceWidth * 0.05),
|
padding: EdgeInsets.symmetric(horizontal: _deviceWidth * 0.05),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
_inputField(),
|
_inputForm(),
|
||||||
_passwordSaveField(),
|
_passwordSaveField(),
|
||||||
_signInField(),
|
_signInButton(_context),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _inputField() {
|
Widget _inputForm() {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: _deviceHeight * 0.25,
|
height: _deviceHeight * 0.27,
|
||||||
child: Form(
|
child: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
onChanged: () {
|
onChanged: () {
|
||||||
@@ -63,64 +73,84 @@ class _LoginScreenState extends State<LoginScreen> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
TextFormField(
|
TextFormField(
|
||||||
|
initialValue: "https://storage.theonasanyas.com",
|
||||||
|
enabled: enableInput,
|
||||||
keyboardType: TextInputType.url,
|
keyboardType: TextInputType.url,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
cursorColor: Colors.white,
|
cursorColor: Colors.black,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
),
|
),
|
||||||
onSaved: (_input) {
|
onSaved: (_input) {
|
||||||
setState(() {
|
setState(() {
|
||||||
urlController = _input!;
|
_url = _input!;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
validator: (_input) {
|
validator: (_input) {
|
||||||
return null;
|
return _input!.isNotEmpty ? null : "nnnns";
|
||||||
},
|
},
|
||||||
decoration: const InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "hosting URL",
|
hintText: "hosting URL",
|
||||||
focusedBorder: UnderlineInputBorder(
|
focusedBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(color: Colors.white)
|
borderSide: BorderSide(color: Colors.white)),
|
||||||
),
|
|
||||||
prefixIcon: Padding(
|
prefixIcon: Padding(
|
||||||
padding: EdgeInsets.all(defaultPadding),
|
padding: EdgeInsets.all(15.0),
|
||||||
child: Icon(Icons.computer_outlined),
|
child: Icon(Icons.computer_outlined),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
|
initialValue: "fluttertest",
|
||||||
|
enabled: enableInput,
|
||||||
keyboardType: TextInputType.emailAddress,
|
keyboardType: TextInputType.emailAddress,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
|
cursorColor: Colors.black,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
),
|
),
|
||||||
onSaved: (_input) {
|
onSaved: (_input) {
|
||||||
|
if (_input == null) {}
|
||||||
setState(() {
|
setState(() {
|
||||||
usernameController = _input!;
|
_username = _input!;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
decoration: const InputDecoration(
|
validator: (_input) {
|
||||||
|
return _input!.isNotEmpty ? null : "nnnns";
|
||||||
|
},
|
||||||
|
decoration: InputDecoration(
|
||||||
hintText: "username",
|
hintText: "username",
|
||||||
|
focusedBorder: UnderlineInputBorder(
|
||||||
|
borderSide: BorderSide(color: Colors.white)),
|
||||||
prefixIcon: Padding(
|
prefixIcon: Padding(
|
||||||
padding: EdgeInsets.all(defaultPadding),
|
padding: EdgeInsets.all(15.0),
|
||||||
child: Icon(Icons.person),
|
child: Icon(Icons.person),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
|
initialValue: "9tWx8XAv545+ijnBxOrh",
|
||||||
|
enabled: enableInput,
|
||||||
keyboardType: TextInputType.visiblePassword,
|
keyboardType: TextInputType.visiblePassword,
|
||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
|
cursorColor: Colors.black,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
obscureText: obscureText,
|
obscureText: obscureText,
|
||||||
onSaved: (_input) {
|
onSaved: (_input) {
|
||||||
setState(() {
|
setState(() {
|
||||||
passwordController = _input!;
|
_password = _input!;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
cursorColor: primaryColor,
|
validator: (_input) {
|
||||||
|
return _input!.isNotEmpty ? null : "nnnns";
|
||||||
|
},
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "Password",
|
hintText: "password",
|
||||||
|
focusedBorder: UnderlineInputBorder(
|
||||||
|
borderSide: BorderSide(color: Colors.white)),
|
||||||
prefixIcon: const Padding(
|
prefixIcon: const Padding(
|
||||||
padding: EdgeInsets.all(defaultPadding),
|
padding: EdgeInsets.all(15.0),
|
||||||
child: Icon(Icons.lock),
|
child: Icon(Icons.lock),
|
||||||
),
|
),
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
@@ -146,50 +176,44 @@ class _LoginScreenState extends State<LoginScreen> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Checkbox(
|
Checkbox(
|
||||||
value: checked,
|
value: savePassword,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
checked = value!;
|
savePassword = value!;
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
const Text('Save Password'),
|
const Text('save password'),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _signInField() {
|
Widget _signInButton(BuildContext _context) {
|
||||||
return ElevatedButton(
|
return _provider.status == AuthStatus.authenticating
|
||||||
onPressed: () {
|
? Align(
|
||||||
login(urlController.value.text, usernameController.value.text,
|
alignment: Alignment.center,
|
||||||
passwordController.value.text)
|
child: CircularProgressIndicator(),
|
||||||
.then((
|
)
|
||||||
status,
|
: SizedBox(
|
||||||
) {
|
height: _deviceHeight * 0.06,
|
||||||
if (status.startsWith('successful')) {
|
width: _deviceWidth * 0.30,
|
||||||
Navigator.push(
|
child: MaterialButton(
|
||||||
context,
|
onPressed: () async {
|
||||||
MaterialPageRoute(
|
enableInput = !enableInput;
|
||||||
builder: (context) {
|
if (_formKey.currentState!.validate()) {
|
||||||
return const WelcomeScreen();
|
//Login User
|
||||||
},
|
await _provider.login(
|
||||||
),
|
_url, _username, _password, savePassword);
|
||||||
);
|
|
||||||
|
|
||||||
SnackBarService.instance.showSnackBarSuccess(status);
|
|
||||||
} else {
|
|
||||||
SnackBarService.instance.showSnackBarError(status);
|
|
||||||
}
|
}
|
||||||
});
|
enableInput = !enableInput;
|
||||||
},
|
},
|
||||||
child: Row(
|
color: Colors.grey,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
child: Text(
|
||||||
children: [
|
'login',
|
||||||
Text(
|
style: TextStyle(
|
||||||
"sign in".toUpperCase(),
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
|
||||||
const Icon(Icons.login)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class WelcomeScreen extends StatefulWidget {
|
|
||||||
const WelcomeScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<WelcomeScreen> createState() => _WelcomeScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _WelcomeScreenState extends State<WelcomeScreen> {
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return const Scaffold(
|
|
||||||
body: Column(
|
|
||||||
children: [
|
|
||||||
|
|
||||||
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,7 +10,7 @@ class NavigationService {
|
|||||||
navigatorKey = GlobalKey<NavigatorState>();
|
navigatorKey = GlobalKey<NavigatorState>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic>? navigateToReplacement(String _routeName) {
|
Future<dynamic> navigateToReplacement(String _routeName) {
|
||||||
return navigatorKey!.currentState!.pushReplacementNamed(_routeName);
|
return navigatorKey!.currentState!.pushReplacementNamed(_routeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+380
-4
@@ -34,7 +34,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.1"
|
||||||
built_collection:
|
built_collection:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: built_collection
|
name: built_collection
|
||||||
sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
|
sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
|
||||||
@@ -81,6 +81,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
|
cross_file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cross_file
|
||||||
|
sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.4+2"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -105,6 +113,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.8"
|
version: "1.0.8"
|
||||||
|
desktop_webview_window:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: desktop_webview_window
|
||||||
|
sha256: "57cf20d81689d5cbb1adfd0017e96b669398a669d927906073b0e42fc64111c0"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.3"
|
||||||
dynamite_runtime:
|
dynamite_runtime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -113,6 +129,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0+1"
|
version: "0.5.0+1"
|
||||||
|
easy_image_viewer:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: easy_image_viewer
|
||||||
|
sha256: fb6cb123c3605552cc91150dcdb50ca977001dcddfb71d20caa0c5edc9a80947
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.5.1"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -137,6 +161,54 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.1"
|
version: "7.0.1"
|
||||||
|
file_icon:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: file_icon
|
||||||
|
sha256: c46b6c24d9595d18995758b90722865baeda407f56308eadd757e1ab913f50a1
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
|
file_picker:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: file_picker
|
||||||
|
sha256: "77f8e81d22d2a07d0dee2c62e1dda71dc1da73bf43bb2d45af09727406167964"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.1.9"
|
||||||
|
file_selector_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file_selector_linux
|
||||||
|
sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.3+2"
|
||||||
|
file_selector_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file_selector_macos
|
||||||
|
sha256: "271ab9986df0c135d45c3cdb6bd0faa5db6f4976d3e4b437cf7d0f258d941bfc"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.4+2"
|
||||||
|
file_selector_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file_selector_platform_interface
|
||||||
|
sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.6.2"
|
||||||
|
file_selector_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file_selector_windows
|
||||||
|
sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.3+4"
|
||||||
fixnum:
|
fixnum:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -150,6 +222,14 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_context_menu:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_context_menu
|
||||||
|
sha256: "5e9c62a5937aba135e3787711b04c73b78729a9751c6c71c2bece4ed9a480d76"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.4"
|
||||||
flutter_lints:
|
flutter_lints:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@@ -158,6 +238,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.0"
|
version: "5.0.0"
|
||||||
|
flutter_plugin_android_lifecycle:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_plugin_android_lifecycle
|
||||||
|
sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.28"
|
||||||
|
flutter_speed_dial:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_speed_dial
|
||||||
|
sha256: "698a037274a66dbae8697c265440e6acb6ab6cae9ac5f95c749e7944d8f28d41"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.0"
|
||||||
|
flutter_spinkit:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_spinkit
|
||||||
|
sha256: d2696eed13732831414595b98863260e33e8882fc069ee80ec35d4ac9ddb0472
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.2.1"
|
||||||
flutter_svg:
|
flutter_svg:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -171,6 +275,22 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_web_auth_2:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_web_auth_2
|
||||||
|
sha256: "3c14babeaa066c371f3a743f204dd0d348b7d42ffa6fae7a9847a521aff33696"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.0"
|
||||||
|
flutter_web_auth_2_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_web_auth_2_platform_interface
|
||||||
|
sha256: c63a472c8070998e4e422f6b34a17070e60782ac442107c70000dd1bed645f4d
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.0"
|
||||||
flutter_web_plugins:
|
flutter_web_plugins:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -192,6 +312,70 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.2"
|
version: "4.1.2"
|
||||||
|
image_picker:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: image_picker
|
||||||
|
sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.2"
|
||||||
|
image_picker_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_android
|
||||||
|
sha256: "317a5d961cec5b34e777b9252393f2afbd23084aa6e60fcf601dcf6341b9ebeb"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.8.12+23"
|
||||||
|
image_picker_for_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_for_web
|
||||||
|
sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.6"
|
||||||
|
image_picker_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_ios
|
||||||
|
sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.8.12+2"
|
||||||
|
image_picker_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_linux
|
||||||
|
sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.1+2"
|
||||||
|
image_picker_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_macos
|
||||||
|
sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.1+2"
|
||||||
|
image_picker_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_platform_interface
|
||||||
|
sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.10.1"
|
||||||
|
image_picker_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image_picker_windows
|
||||||
|
sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.1+1"
|
||||||
intl:
|
intl:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -241,7 +425,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "5.1.1"
|
version: "5.1.1"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: logging
|
name: logging
|
||||||
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
|
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
|
||||||
@@ -272,6 +456,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.15.0"
|
version: "1.15.0"
|
||||||
|
mime:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: mime
|
||||||
|
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
|
nested:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: nested
|
||||||
|
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
nextcloud:
|
nextcloud:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -296,6 +496,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.0"
|
||||||
|
path_provider:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: path_provider
|
||||||
|
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.5"
|
||||||
|
path_provider_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_android
|
||||||
|
sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.17"
|
||||||
|
path_provider_foundation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_foundation
|
||||||
|
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.1"
|
||||||
path_provider_linux:
|
path_provider_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -320,6 +544,54 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.3.0"
|
||||||
|
permission_handler:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: permission_handler
|
||||||
|
sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "11.4.0"
|
||||||
|
permission_handler_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_android
|
||||||
|
sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "12.1.0"
|
||||||
|
permission_handler_apple:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_apple
|
||||||
|
sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "9.4.7"
|
||||||
|
permission_handler_html:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_html
|
||||||
|
sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.3+5"
|
||||||
|
permission_handler_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_platform_interface
|
||||||
|
sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.3.0"
|
||||||
|
permission_handler_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_windows
|
||||||
|
sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.1"
|
||||||
petitparser:
|
petitparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -352,6 +624,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.9.1"
|
version: "3.9.1"
|
||||||
|
provider:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: provider
|
||||||
|
sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.5"
|
||||||
quiver:
|
quiver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -364,10 +644,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: shared_preferences
|
name: shared_preferences
|
||||||
sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a"
|
sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.2"
|
version: "2.5.3"
|
||||||
shared_preferences_android:
|
shared_preferences_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -469,6 +749,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.3"
|
version: "0.7.3"
|
||||||
|
timeago:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: timeago
|
||||||
|
sha256: b05159406a97e1cbb2b9ee4faa9fb096fe0e2dfcd8b08fcd2a00553450d3422e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.7.1"
|
||||||
timezone:
|
timezone:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -485,6 +773,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.0"
|
version: "1.4.0"
|
||||||
|
units_converter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: units_converter
|
||||||
|
sha256: dfb40a9bd0df48701466ae17fd9a763eed3abe9b98b97be1d04a2fecb99673a6
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.3"
|
||||||
universal_io:
|
universal_io:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -501,6 +797,70 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
|
url_launcher:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: url_launcher
|
||||||
|
sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.3.1"
|
||||||
|
url_launcher_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_android
|
||||||
|
sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.3.16"
|
||||||
|
url_launcher_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_ios
|
||||||
|
sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.3.3"
|
||||||
|
url_launcher_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_linux
|
||||||
|
sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.1"
|
||||||
|
url_launcher_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_macos
|
||||||
|
sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.2"
|
||||||
|
url_launcher_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_platform_interface
|
||||||
|
sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.2"
|
||||||
|
url_launcher_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_web
|
||||||
|
sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.1"
|
||||||
|
url_launcher_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: url_launcher_windows
|
||||||
|
sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.4"
|
||||||
vector_graphics:
|
vector_graphics:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -557,6 +917,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.1"
|
||||||
|
win32:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: win32
|
||||||
|
sha256: daf97c9d80197ed7b619040e86c8ab9a9dad285e7671ee7390f9180cc828a51e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.10.1"
|
||||||
|
window_to_front:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: window_to_front
|
||||||
|
sha256: "7aef379752b7190c10479e12b5fd7c0b9d92adc96817d9e96c59937929512aee"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.3"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
+19
-4
@@ -12,14 +12,29 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
|
||||||
cupertino_icons: ^1.0.8
|
cupertino_icons: ^1.0.8
|
||||||
flutter_svg: ^2.0.17
|
flutter_svg: ^2.0.17
|
||||||
http: ^1.3.0
|
http: ^1.3.0
|
||||||
intl: ^0.20.2
|
shared_preferences: ^2.5.3
|
||||||
shared_preferences: ^2.5.2
|
|
||||||
nextcloud: ^8.1.0
|
nextcloud: ^8.1.0
|
||||||
|
provider: ^6.1.2
|
||||||
|
image_picker: ^1.1.2
|
||||||
|
timeago: ^3.7.0
|
||||||
|
easy_image_viewer: ^1.5.1
|
||||||
|
permission_handler: ^11.4.0
|
||||||
|
path_provider: ^2.1.5
|
||||||
|
mime: ^2.0.0
|
||||||
|
built_collection: ^5.1.1
|
||||||
|
flutter_web_auth_2: ^4.1.0
|
||||||
|
logging: ^1.3.0
|
||||||
|
url_launcher: ^6.3.1
|
||||||
|
flutter_spinkit: ^5.2.1
|
||||||
|
units_converter: ^3.0.3
|
||||||
|
file_icon: ^1.0.0
|
||||||
|
intl: ^0.20.2
|
||||||
|
flutter_speed_dial: ^7.0.0
|
||||||
|
file_picker: ^10.1.9
|
||||||
|
flutter_context_menu: ^0.2.4
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
Reference in New Issue
Block a user