Compare commits

..

No commits in common. "8d11584811a1a7bc6000afe0690b7e12ba19064b" and "d3e54eb1d579da4549b5be6445e3fe7394284419" have entirely different histories.

23 changed files with 523 additions and 251 deletions

View file

@ -4,7 +4,7 @@ name: default
steps:
- name: build
image: cirrusci/flutter:3.3.9
image: cirrusci/flutter:3.0.5
commands:
- flutter doctor
- flutter pub get

View file

@ -1,13 +1,11 @@
# CHANGELOG
## 1.5.0+16 - UNRELEASED
* Switched to Material You defaulting to blue swatch colors respecting dark mode
* Switched to Material You navigation bar and removed unsupported swipe navigation
## 1.4.3+16 - UNRELEASED
* Increased target SDK to `33`
* Increased dart to `>= 2.18.6`
* Increased dart to `>= 2.17.3`
* Indicate configuration loading in profile view
* Switched linked git repository away from GitHub
* Updated internal dependencies
* Updated dependencies
## 1.4.2+15
* Minor cleanup

View file

@ -1,10 +1,10 @@
import 'package:dynamic_color/dynamic_color.dart';
import 'package:flutter/material.dart';
import 'package:flutter_translate/flutter_translate.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'package:provider/provider.dart';
import 'core/enums/refresh_event.dart';
import 'core/enums/swipe_event.dart';
import 'core/manager/dialog_manager.dart';
import 'core/manager/lifecycle_manager.dart';
import 'core/models/session.dart';
@ -12,14 +12,13 @@ import 'core/services/dialog_service.dart';
import 'core/services/navigation_service.dart';
import 'core/services/refresh_service.dart';
import 'core/services/session_service.dart';
import 'core/services/swipe_service.dart';
import 'locator.dart';
import 'ui/app_router.dart';
import 'ui/shared/app_colors.dart';
import 'ui/views/startup_view.dart';
class MyApp extends StatelessWidget {
static final _defaultLightColorScheme = ColorScheme.fromSwatch(primarySwatch: myColor, brightness: Brightness.light);
static final _defaultDarkColorScheme = ColorScheme.fromSwatch(primarySwatch: myColor, brightness: Brightness.dark);
MyApp() {
initializeDateFormatting('en');
@ -31,32 +30,34 @@ class MyApp extends StatelessWidget {
return LocalizationProvider(
state: LocalizationProvider.of(context).state,
child: StreamProvider<SwipeEvent?>(
initialData: null,
create: (context) => locator<SwipeService>().swipeEventController.stream,
child: StreamProvider<RefreshEvent?>(
initialData: null,
create: (context) => locator<RefreshService>().refreshEventController.stream,
child: StreamProvider<Session?>(
initialData: Session.initial(),
create: (context) => locator<SessionService>().sessionController.stream,
child: LifeCycleManager(child: DynamicColorBuilder(builder: (lightColorScheme, darkColorScheme) {
return MaterialApp(
child: LifeCycleManager(
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: translate('app.title'),
builder: (context, child) => Navigator(
key: locator<DialogService>().dialogNavigationKey,
onGenerateRoute: (settings) => MaterialPageRoute(builder: (context) => DialogManager(child: child)),
onGenerateRoute: (settings) =>
MaterialPageRoute(builder: (context) => DialogManager(child: child)),
),
theme: ThemeData(
useMaterial3: true,
brightness: Brightness.light,
colorScheme: lightColorScheme ?? _defaultLightColorScheme),
darkTheme: ThemeData(useMaterial3: true, colorScheme: darkColorScheme ?? _defaultDarkColorScheme),
primarySwatch: primaryAccentColor as MaterialColor?,
primaryColor: primaryAccentColor),
onGenerateRoute: AppRouter.generateRoute,
navigatorKey: locator<NavigationService>().navigationKey,
home: StartUpView(),
supportedLocales: localizationDelegate.supportedLocales,
locale: localizationDelegate.currentLocale,
);
})),
)));
)),
))));
}
}

View file

@ -0,0 +1 @@
enum SwipeEvent { Start, Left, Right, End }

View file

@ -0,0 +1,13 @@
import 'dart:async';
import '../enums/swipe_event.dart';
class SwipeService {
StreamController<SwipeEvent> swipeEventController = StreamController<SwipeEvent>.broadcast();
void addEvent(SwipeEvent event) {
if (swipeEventController.hasListener) {
swipeEventController.add(event);
}
}
}

View file

@ -12,6 +12,7 @@ import 'package:receive_sharing_intent/receive_sharing_intent.dart';
import '../../locator.dart';
import '../enums/error_code.dart';
import '../enums/refresh_event.dart';
import '../enums/swipe_event.dart';
import '../enums/viewstate.dart';
import '../error/rest_service_exception.dart';
import '../error/service_exception.dart';
@ -21,6 +22,7 @@ import '../models/rest/uploaded_response.dart';
import '../services/file_service.dart';
import '../services/link_service.dart';
import '../services/refresh_service.dart';
import '../services/swipe_service.dart';
import '../util/logger.dart';
import '../util/paste_util.dart';
import 'base_model.dart';
@ -30,6 +32,7 @@ class UploadModel extends BaseModel {
final FileService _fileService = locator<FileService>();
final LinkService _linkService = locator<LinkService>();
final RefreshService _refreshService = locator<RefreshService>();
final SwipeService _swipeService = locator<SwipeService>();
TextEditingController _pasteTextController = TextEditingController();
bool pasteTextTouched = false;
@ -64,6 +67,9 @@ class UploadModel extends BaseModel {
});
}).toList();
setStateView(ViewState.Idle);
if (paths!.isNotEmpty && paths!.length > 0) {
_swipeService.addEvent(SwipeEvent.Start);
}
}
}, onError: (err) {
_errorIntentHandle(err);
@ -82,6 +88,9 @@ class UploadModel extends BaseModel {
});
}).toList();
setStateView(ViewState.Idle);
if (paths!.isNotEmpty && paths!.length > 0) {
_swipeService.addEvent(SwipeEvent.Start);
}
}
}, onError: (err) {
_errorIntentHandle(err);
@ -93,6 +102,7 @@ class UploadModel extends BaseModel {
setStateView(ViewState.Busy);
pasteTextController.text = value;
setStateView(ViewState.Idle);
_swipeService.addEvent(SwipeEvent.Start);
}
}, onError: (err) {
_errorIntentHandle(err);
@ -104,6 +114,9 @@ class UploadModel extends BaseModel {
setStateView(ViewState.Busy);
pasteTextController.text = value;
setStateView(ViewState.Idle);
if (paths!.isNotEmpty && paths!.length > 0) {
_swipeService.addEvent(SwipeEvent.Start);
}
}
}, onError: (err) {
_errorIntentHandle(err);
@ -115,6 +128,8 @@ class UploadModel extends BaseModel {
errorMessage = translate('upload.retrieval_intent');
_logger.e('Error while retrieving shared data: $err');
setStateView(ViewState.Idle);
_swipeService.addEvent(SwipeEvent.Start);
}
String? generatePasteLinks(Map<String, bool>? uploads, String url) {

View file

@ -11,6 +11,7 @@ import 'core/services/permission_service.dart';
import 'core/services/refresh_service.dart';
import 'core/services/session_service.dart';
import 'core/services/storage_service.dart';
import 'core/services/swipe_service.dart';
import 'core/services/user_service.dart';
import 'core/viewmodels/about_model.dart';
import 'core/viewmodels/history_model.dart';
@ -41,6 +42,7 @@ void setupLocator() {
locator.registerLazySingleton(() => LinkService());
locator.registerLazySingleton(() => PermissionService());
locator.registerLazySingleton(() => RefreshService());
locator.registerLazySingleton(() => SwipeService());
/// view models
locator.registerFactory(() => StartUpViewModel());

View file

@ -1,5 +1,10 @@
import 'package:flutter/material.dart';
const Color backgroundColor = whiteColor;
/// Colors
const Color primaryBackgroundColor = whiteColor;
const Map<int, Color> colors = {
50: Color.fromRGBO(63, 69, 75, .1),
100: Color.fromRGBO(63, 69, 75, .2),
@ -14,6 +19,8 @@ const Map<int, Color> colors = {
};
const MaterialColor myColor = MaterialColor(0xFF3F454B, colors);
const Color primaryAccentColor = myColor;
const Color buttonBackgroundColor = primaryAccentColor;
const Color buttonForegroundColor = whiteColor;
const Color blueColor = Colors.blue;
const Color whiteColor = Colors.white;

View file

@ -1,3 +1,4 @@
import 'package:flutter/material.dart';
const headerStyle = TextStyle(fontSize: 35, fontWeight: FontWeight.w900);
const subHeaderStyle = TextStyle(fontSize: 16.0, fontWeight: FontWeight.w500);

View file

@ -6,6 +6,7 @@ import '../../core/enums/viewstate.dart';
import '../../core/viewmodels/about_model.dart';
import '../../ui/shared/text_styles.dart';
import '../../ui/shared/ui_helpers.dart';
import '../shared/app_colors.dart';
import '../widgets/my_appbar.dart';
import 'base_view.dart';
@ -30,6 +31,7 @@ class AboutView extends StatelessWidget {
title: Text(translate('titles.about')),
enableAbout: false,
),
backgroundColor: backgroundColor,
body: model.state == ViewState.Busy
? Center(child: CircularProgressIndicator())
: Container(

View file

@ -13,6 +13,7 @@ import '../../core/viewmodels/history_model.dart';
import '../../ui/widgets/centered_error_row.dart';
import '../shared/app_colors.dart';
import '../widgets/my_appbar.dart';
import '../widgets/swipe_navigation.dart';
import 'base_view.dart';
class HistoryView extends StatelessWidget {
@ -25,8 +26,10 @@ class HistoryView extends StatelessWidget {
model.init();
return model.getHistory();
},
builder: (context, model, child) =>
Scaffold(appBar: MyAppBar(title: Text(translate('titles.history'))), body: _render(model, context)),
builder: (context, model, child) => Scaffold(
appBar: MyAppBar(title: Text(translate('titles.history'))),
backgroundColor: backgroundColor,
body: SwipeNavigation(child: _render(model, context))),
);
}

View file

@ -3,6 +3,7 @@ import 'package:flutter_translate/flutter_translate.dart';
import '../../core/enums/viewstate.dart';
import '../../core/viewmodels/home_model.dart';
import '../shared/app_colors.dart';
import '../widgets/my_appbar.dart';
import 'base_view.dart';
@ -14,6 +15,7 @@ class HomeView extends StatelessWidget {
return BaseView<HomeModel>(
builder: (context, model, child) => Scaffold(
appBar: MyAppBar(title: Text(translate('app.title'))),
backgroundColor: backgroundColor,
body: model.state == ViewState.Busy ? Center(child: CircularProgressIndicator()) : Container()),
);
}

View file

@ -36,6 +36,7 @@ class LoginView extends StatelessWidget {
onModelReady: (model) => model.init(),
builder: (context, model, child) => Scaffold(
appBar: MyAppBar(title: Text(translate('titles.login'))),
backgroundColor: backgroundColor,
body: model.state == ViewState.Busy
? Center(child: CircularProgressIndicator())
: ListView(
@ -55,7 +56,7 @@ class LoginView extends StatelessWidget {
style: subHeaderStyle,
),
InkWell(
child: Icon(Icons.help),
child: Icon(Icons.help, color: buttonBackgroundColor),
onTap: () {
_dialogService.showDialog(
title: translate('login.compatibility_dialog.title'),
@ -84,7 +85,7 @@ class LoginView extends StatelessWidget {
apiKeyController: model.apiKeyController),
UIHelper.verticalSpaceMedium(),
ElevatedButton(
child: Text(translate('login.button')),
child: Text(translate('login.button'), style: TextStyle(color: buttonForegroundColor)),
onPressed: () async {
var loginSuccess = await model.login();
if (loginSuccess) {

View file

@ -1,70 +0,0 @@
import 'package:fbmobile/core/util/logger.dart';
import 'package:fbmobile/ui/views/profile_view.dart';
import 'package:fbmobile/ui/views/upload_view.dart';
import 'package:flutter/material.dart';
import 'package:logger/logger.dart';
import '../shared/app_colors.dart';
import 'history_view.dart';
class AuthenticatedNavBarView extends StatefulWidget {
@override
AuthenticatedNavBarState createState() => AuthenticatedNavBarState();
}
class AuthenticatedNavBarState extends State<AuthenticatedNavBarView> with SingleTickerProviderStateMixin {
final Logger _logger = getLogger();
int _currentTabIndex = 0;
void updateIndex(int targetIndex) {
setState(() {
_currentTabIndex = targetIndex;
_logger.d("Changing current tab index to '$targetIndex'");
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: NavigationBar(
key: UniqueKey(),
onDestinationSelected: (int index) {
updateIndex(index);
},
selectedIndex: _currentTabIndex,
labelBehavior: NavigationDestinationLabelBehavior.alwaysHide,
destinations: const <Widget>[
NavigationDestination(
icon: Icon(Icons.upload_outlined),
label: 'Upload',
),
NavigationDestination(
icon: Icon(Icons.history_outlined),
label: 'History',
),
NavigationDestination(
icon: Icon(Icons.person_outlined),
label: 'Profile',
),
],
),
body: <Widget>[
Container(
color: myColor,
alignment: Alignment.center,
child: UploadView(),
),
Container(
color: myColor,
alignment: Alignment.center,
child: HistoryView(),
),
Container(
color: myColor,
alignment: Alignment.center,
child: ProfileView(),
),
][_currentTabIndex],
);
}
}

View file

@ -10,6 +10,7 @@ import '../shared/app_colors.dart';
import '../shared/text_styles.dart';
import '../shared/ui_helpers.dart';
import '../widgets/my_appbar.dart';
import '../widgets/swipe_navigation.dart';
import 'base_view.dart';
class ProfileView extends StatelessWidget {
@ -18,8 +19,10 @@ class ProfileView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BaseView<ProfileModel>(
builder: (context, model, child) =>
Scaffold(appBar: MyAppBar(title: Text(translate('titles.profile'))), body: _render(model, context)));
builder: (context, model, child) => Scaffold(
appBar: MyAppBar(title: Text(translate('titles.profile'))),
backgroundColor: backgroundColor,
body: SwipeNavigation(child: _render(model, context))));
}
Widget _render(ProfileModel model, BuildContext context) {
@ -57,13 +60,15 @@ class ProfileView extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CircularProgressIndicator(),
Text(translate('profile.show_config_loading')),
Text(translate('profile.show_config_loading'),
style: TextStyle(color: buttonBackgroundColor))
],
))
: ElevatedButton.icon(
icon: Icon(Icons.settings, color: blueColor),
label: Text(
translate('profile.show_config'),
style: TextStyle(color: buttonForegroundColor),
),
onPressed: () async {
await model.showConfig(url);
@ -75,6 +80,7 @@ class ProfileView extends StatelessWidget {
icon: Icon(Icons.lock, color: orangeColor),
label: Text(
translate('profile.reveal_api_key'),
style: TextStyle(color: buttonForegroundColor),
),
onPressed: () {
model.revealApiKey(apiKey);
@ -86,6 +92,7 @@ class ProfileView extends StatelessWidget {
icon: Icon(Icons.exit_to_app, color: redColor),
label: Text(
translate('profile.logout'),
style: TextStyle(color: buttonForegroundColor),
),
onPressed: () async {
await model.logout();

View file

@ -0,0 +1,67 @@
import 'package:flutter/material.dart';
import 'package:flutter_translate/flutter_translate.dart';
import '../shared/app_colors.dart';
import 'login_view.dart';
class AnonymousTabBarView extends StatefulWidget {
@override
AnonymousTabBarState createState() => AnonymousTabBarState();
}
class AnonymousTabBarState extends State<AnonymousTabBarView> with SingleTickerProviderStateMixin {
TabController? _tabController;
int _currentTabIndex = 0;
List<Widget> _realPages = [LoginView()];
List<Widget> _tabPages = [LoginView()];
List<bool> _hasInit = [true];
List<Widget> _tabsButton = [
Tab(
icon: Icon(Icons.person_outline, color: blueColor),
child: Text(
translate('tabs.login'),
style: TextStyle(color: blueColor),
),
)
];
@override
void initState() {
super.initState();
_tabController = TabController(length: _realPages.length, vsync: this)
..addListener(() {
int selectedIndex = _tabController!.index;
if (_currentTabIndex != selectedIndex) {
if (!_hasInit[selectedIndex]) {
_tabPages[selectedIndex] = _realPages[selectedIndex];
_hasInit[selectedIndex] = true;
}
setState(() => _currentTabIndex = selectedIndex);
}
});
}
@override
void dispose() {
_tabController!.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: IndexedStack(index: _currentTabIndex, children: _tabPages),
bottomNavigationBar: BottomAppBar(
child: TabBar(
labelColor: primaryAccentColor,
indicatorColor: blueColor,
indicatorWeight: 3.0,
tabs: _tabsButton,
controller: _tabController,
),
),
);
}
}

View file

@ -0,0 +1,149 @@
import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_translate/flutter_translate.dart';
import 'package:logger/logger.dart';
import '../../core/enums/swipe_event.dart';
import '../../core/services/swipe_service.dart';
import '../../core/util/logger.dart';
import '../../locator.dart';
import '../shared/app_colors.dart';
import 'history_view.dart';
import 'profile_view.dart';
import 'upload_view.dart';
class AuthenticatedTabBarView extends StatefulWidget {
@override
AuthenticatedTabBarState createState() => AuthenticatedTabBarState();
}
class AuthenticatedTabBarState extends State<AuthenticatedTabBarView> with SingleTickerProviderStateMixin {
final Logger _logger = getLogger();
final SwipeService _swipeService = locator<SwipeService>();
late StreamSubscription _swipeEventSubscription;
TabController? _tabController;
int _currentTabIndex = 0;
List<Widget> _realPages = [UploadView(), HistoryView(), ProfileView()];
List<Widget> _tabPages = [
UploadView(),
Container(),
Container(),
];
List<bool> _hasInit = [true, false, false];
@override
void initState() {
super.initState();
_tabController = TabController(length: _realPages.length, vsync: this)
..addListener(() {
int selectedIndex = _tabController!.index;
if (_currentTabIndex != selectedIndex) {
if (!_hasInit[selectedIndex]) {
_tabPages[selectedIndex] = _realPages[selectedIndex];
_hasInit[selectedIndex] = true;
}
setState(() => _currentTabIndex = selectedIndex);
}
});
_swipeEventSubscription = _swipeService.swipeEventController.stream.listen((SwipeEvent event) {
_logger.d('Received a swipe event for the authenticated tab bar: $event');
int targetIndex = _currentTabIndex;
if (SwipeEvent.Left == event) {
targetIndex = min(_currentTabIndex + 1, _realPages.length - 1);
}
if (SwipeEvent.Right == event) {
targetIndex = max(_currentTabIndex - 1, 0);
}
if (SwipeEvent.Start == event) {
targetIndex = 0;
}
if (SwipeEvent.End == event) {
targetIndex = _tabPages.length - 1;
}
_logger.d("Changing to tab '$targetIndex' because of a swipe event '$event'");
_tabController!.animateTo(targetIndex);
});
}
@override
void dispose() {
_tabController!.dispose();
_swipeEventSubscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double yourWidth = width / 3;
double yourHeight = 55;
Color colorTabItem0 = _currentTabIndex == 0 ? blueColor : primaryAccentColor;
Color colorTabItem1 = _currentTabIndex == 1 ? blueColor : primaryAccentColor;
Color colorTabItem2 = _currentTabIndex == 2 ? blueColor : primaryAccentColor;
List<Widget> _tabsButton = [
Container(
width: yourWidth,
height: yourHeight,
alignment: Alignment.center,
child: Tab(
icon: Icon(
_currentTabIndex == 0 ? Icons.upload_outlined : Icons.upload_rounded,
color: colorTabItem0,
),
child: Text(translate('tabs.upload'), style: TextStyle(color: colorTabItem0)),
),
),
Container(
width: yourWidth,
height: yourHeight,
alignment: Alignment.center,
child: Tab(
icon: Icon(
_currentTabIndex == 1 ? Icons.history_outlined : Icons.history_rounded,
color: colorTabItem1,
),
child: Text(translate('tabs.history'), style: TextStyle(color: colorTabItem1)),
),
),
Container(
width: yourWidth,
height: yourHeight,
alignment: Alignment.center,
child: Tab(
icon: Icon(
_currentTabIndex == 2 ? Icons.person_outlined : Icons.person_rounded,
color: colorTabItem2,
),
child: Text(translate('tabs.profile'), style: TextStyle(color: colorTabItem2)),
),
),
];
return Scaffold(
body: IndexedStack(index: _currentTabIndex, children: _tabPages),
bottomNavigationBar: BottomAppBar(
child: TabBar(
indicatorSize: TabBarIndicatorSize.label,
labelColor: primaryAccentColor,
indicatorColor: blueColor,
indicatorWeight: 3.0,
labelPadding: EdgeInsets.all(0),
tabs: _tabsButton,
isScrollable: true,
controller: _tabController,
)),
);
}
}

View file

@ -1,9 +1,9 @@
import 'package:fbmobile/ui/views/login_view.dart';
import 'package:fbmobile/ui/views/navbar_authenticated.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../core/models/session.dart';
import 'tabbar_anonymous.dart';
import 'tabbar_authenticated.dart';
class TabBarContainerView extends StatelessWidget {
@override
@ -12,11 +12,9 @@ class TabBarContainerView extends StatelessWidget {
bool isAuthenticated = currentSession != null ? currentSession.apiKey.isNotEmpty : false;
if (isAuthenticated) {
return AuthenticatedNavBarView();
return AuthenticatedTabBarView();
}
return Container(
child: LoginView(),
);
return AnonymousTabBarView();
}
}

View file

@ -9,6 +9,7 @@ import '../../core/viewmodels/upload_model.dart';
import '../shared/app_colors.dart';
import '../widgets/centered_error_row.dart';
import '../widgets/my_appbar.dart';
import '../widgets/swipe_navigation.dart';
import 'base_view.dart';
class UploadView extends StatelessWidget {
@ -18,8 +19,10 @@ class UploadView extends StatelessWidget {
Widget build(BuildContext context) {
return BaseView<UploadModel>(
onModelReady: (model) => model.init(),
builder: (context, model, child) =>
Scaffold(appBar: MyAppBar(title: Text(translate('titles.upload'))), body: _render(model, context)));
builder: (context, model, child) => Scaffold(
appBar: MyAppBar(title: Text(translate('titles.upload'))),
backgroundColor: backgroundColor,
body: SwipeNavigation(child: _render(model, context))));
}
bool _isUploadButtonEnabled(UploadModel model) {
@ -52,6 +55,7 @@ class UploadView extends StatelessWidget {
decoration: InputDecoration(
prefixIcon: Icon(
Icons.text_snippet,
color: buttonBackgroundColor,
),
suffixIcon: IconButton(
onPressed: () => model.pasteTextController.clear(),
@ -79,6 +83,7 @@ class UploadView extends StatelessWidget {
onPressed: () => model.openFileExplorer(),
label: Text(
translate('upload.open_file_explorer'),
style: TextStyle(color: buttonForegroundColor),
)),
ElevatedButton.icon(
icon: Icon(Icons.cancel, color: orangeColor),
@ -87,6 +92,7 @@ class UploadView extends StatelessWidget {
: null,
label: Text(
translate('upload.clear_temporary_files'),
style: TextStyle(color: buttonForegroundColor),
)),
],
)),
@ -135,6 +141,7 @@ class UploadView extends StatelessWidget {
icon: Icon(Icons.upload_rounded, color: greenColor),
label: Text(
translate('upload.upload'),
style: TextStyle(color: buttonForegroundColor),
)),
])),
model.errorMessage != null && model.errorMessage!.isNotEmpty

View file

@ -1,5 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../shared/app_colors.dart';
import '../widgets/about_iconbutton.dart';
class MyAppBar extends AppBar {
@ -7,7 +9,15 @@ class MyAppBar extends AppBar {
static final List<Widget> aboutDisabledWidgets = [];
MyAppBar({Key? key, required Widget title, List<Widget>? actionWidgets, bool enableAbout = true})
: super(key: key, title: Row(children: <Widget>[title]), actions: _renderIconButtons(actionWidgets, enableAbout));
: super(
key: key,
title: Row(children: <Widget>[title]),
actions: _renderIconButtons(actionWidgets, enableAbout),
systemOverlayStyle: SystemUiOverlayStyle(
systemNavigationBarColor: primaryAccentColor, // Navigation bar
statusBarColor: primaryAccentColor, // Status bar
),
backgroundColor: primaryAccentColor);
static List<Widget> _renderIconButtons(List<Widget>? actionWidgets, bool aboutEnabled) {
if (actionWidgets == null) {

View file

@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
import 'package:simple_gesture_detector/simple_gesture_detector.dart';
import '../../core/enums/swipe_event.dart';
import '../../core/services/swipe_service.dart';
import '../../locator.dart';
class SwipeNavigation extends StatefulWidget {
/// Widget to be augmented with gesture detection.
final Widget? child;
/// Creates a [SwipeNavigation] widget.
const SwipeNavigation({
Key? key,
this.child,
}) : super(key: key);
@override
_SwipeNavigationState createState() => _SwipeNavigationState();
}
class _SwipeNavigationState extends State<SwipeNavigation> {
final SwipeService _swipeService = locator<SwipeService>();
void _onHorizontalSwipe(SwipeDirection direction) {
if (direction == SwipeDirection.left) {
_swipeService.addEvent(SwipeEvent.Left);
} else {
_swipeService.addEvent(SwipeEvent.Right);
}
}
@override
Widget build(BuildContext context) {
return SimpleGestureDetector(onHorizontalSwipe: _onHorizontalSwipe, child: widget.child!);
}
}

View file

@ -7,14 +7,14 @@ packages:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
source: hosted
version: "50.0.0"
version: "46.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "5.2.0"
version: "4.6.0"
args:
dependency: transitive
description:
@ -28,7 +28,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.9.0"
version: "2.8.2"
boolean_selector:
dependency: transitive
description:
@ -42,14 +42,14 @@ packages:
name: build
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.1"
version: "2.3.0"
build_config:
dependency: transitive
description:
name: build_config
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
version: "1.1.0"
build_daemon:
dependency: transitive
description:
@ -63,21 +63,21 @@ packages:
name: build_resolvers
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.0.9"
build_runner:
dependency: "direct dev"
description:
name: build_runner
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.2"
version: "2.2.0"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
url: "https://pub.dartlang.org"
source: hosted
version: "7.2.7"
version: "7.2.3"
built_collection:
dependency: transitive
description:
@ -91,21 +91,28 @@ packages:
name: built_value
url: "https://pub.dartlang.org"
source: hosted
version: "8.4.2"
version: "8.4.0"
built_value_generator:
dependency: "direct dev"
description:
name: built_value_generator
url: "https://pub.dartlang.org"
source: hosted
version: "8.4.2"
version: "8.4.0"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
version: "1.2.0"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
checked_yaml:
dependency: transitive
description:
@ -126,14 +133,14 @@ packages:
name: clock
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
version: "1.1.0"
code_builder:
dependency: transitive
description:
name: code_builder
url: "https://pub.dartlang.org"
source: hosted
version: "4.3.0"
version: "4.2.0"
collection:
dependency: transitive
description:
@ -147,14 +154,7 @@ packages:
name: convert
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.1"
cross_file:
dependency: transitive
description:
name: cross_file
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.3+2"
version: "3.0.2"
crypto:
dependency: transitive
description:
@ -175,14 +175,7 @@ packages:
name: dart_style
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.4"
dynamic_color:
dependency: "direct main"
description:
name: dynamic_color
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.4"
version: "2.2.3"
expandable:
dependency: "direct main"
description:
@ -196,7 +189,7 @@ packages:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
version: "1.3.0"
ffi:
dependency: transitive
description:
@ -210,14 +203,14 @@ packages:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.4"
version: "6.1.2"
file_picker:
dependency: "direct main"
description:
name: file_picker
url: "https://pub.dartlang.org"
source: hosted
version: "5.2.4"
version: "5.0.1"
fixnum:
dependency: transitive
description:
@ -272,7 +265,7 @@ packages:
name: frontend_server_client
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.0"
version: "2.1.3"
get_it:
dependency: "direct main"
description:
@ -286,14 +279,14 @@ packages:
name: glob
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
version: "2.1.0"
graphs:
dependency: transitive
description:
name: graphs
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.0"
version: "2.1.0"
http:
dependency: "direct main"
description:
@ -314,7 +307,7 @@ packages:
name: http_parser
url: "https://pub.dartlang.org"
source: hosted
version: "4.0.2"
version: "4.0.1"
intl:
dependency: transitive
description:
@ -342,14 +335,14 @@ packages:
name: json_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "4.7.0"
version: "4.6.0"
json_serializable:
dependency: "direct dev"
description:
name: json_serializable
url: "https://pub.dartlang.org"
source: hosted
version: "6.5.4"
version: "6.3.1"
linkify:
dependency: transitive
description:
@ -370,35 +363,35 @@ packages:
name: logging
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
version: "1.0.2"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.12"
version: "0.12.11"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.5"
version: "0.1.4"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0"
version: "1.7.0"
mime:
dependency: transitive
description:
name: mime
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
version: "1.0.2"
nested:
dependency: transitive
description:
@ -419,42 +412,49 @@ packages:
name: package_info_plus
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.2"
version: "1.4.3+1"
package_info_plus_linux:
dependency: transitive
description:
name: package_info_plus_linux
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
package_info_plus_macos:
dependency: transitive
description:
name: package_info_plus_macos
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
package_info_plus_platform_interface:
dependency: transitive
description:
name: package_info_plus_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
version: "1.0.2"
package_info_plus_web:
dependency: transitive
description:
name: package_info_plus_web
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
package_info_plus_windows:
dependency: transitive
description:
name: package_info_plus_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.2"
path_provider:
dependency: transitive
description:
name: path_provider
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.11"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.22"
path_provider_ios:
dependency: transitive
description:
name: path_provider_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.11"
version: "1.8.1"
path_provider_linux:
dependency: transitive
description:
@ -462,62 +462,55 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.7"
path_provider_macos:
dependency: transitive
description:
name: path_provider_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.6"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.5"
version: "2.0.4"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
version: "2.1.2"
permission_handler:
dependency: "direct main"
description:
name: permission_handler
url: "https://pub.dartlang.org"
source: hosted
version: "10.2.0"
version: "10.0.0"
permission_handler_android:
dependency: transitive
description:
name: permission_handler_android
url: "https://pub.dartlang.org"
source: hosted
version: "10.2.0"
version: "10.0.0"
permission_handler_apple:
dependency: transitive
description:
name: permission_handler_apple
url: "https://pub.dartlang.org"
source: hosted
version: "9.0.7"
version: "9.0.4"
permission_handler_platform_interface:
dependency: transitive
description:
name: permission_handler_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.9.0"
version: "3.7.0"
permission_handler_windows:
dependency: transitive
description:
name: permission_handler_windows
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2"
version: "0.1.0"
platform:
dependency: transitive
description:
@ -531,7 +524,7 @@ packages:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
version: "2.1.2"
pool:
dependency: transitive
description:
@ -552,21 +545,21 @@ packages:
name: provider
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.5"
version: "6.0.3"
pub_semver:
dependency: transitive
description:
name: pub_semver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
version: "2.1.1"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
version: "1.2.0"
quiver:
dependency: transitive
description:
@ -587,14 +580,42 @@ packages:
name: share_plus
url: "https://pub.dartlang.org"
source: hosted
version: "6.3.0"
version: "4.0.10+1"
share_plus_linux:
dependency: transitive
description:
name: share_plus_linux
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.0"
share_plus_macos:
dependency: transitive
description:
name: share_plus_macos
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
share_plus_platform_interface:
dependency: transitive
description:
name: share_plus_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.0"
version: "3.0.3"
share_plus_web:
dependency: transitive
description:
name: share_plus_web
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
share_plus_windows:
dependency: transitive
description:
name: share_plus_windows
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
shared_preferences:
dependency: "direct main"
description:
@ -608,7 +629,7 @@ packages:
name: shared_preferences_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.14"
version: "2.0.12"
shared_preferences_ios:
dependency: transitive
description:
@ -622,7 +643,7 @@ packages:
name: shared_preferences_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
version: "2.1.1"
shared_preferences_macos:
dependency: transitive
description:
@ -636,7 +657,7 @@ packages:
name: shared_preferences_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.0.0"
shared_preferences_web:
dependency: transitive
description:
@ -650,21 +671,28 @@ packages:
name: shared_preferences_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
version: "2.1.1"
shelf:
dependency: transitive
description:
name: shelf
url: "https://pub.dartlang.org"
source: hosted
version: "1.4.0"
version: "1.3.2"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3"
version: "1.0.2"
simple_gesture_detector:
dependency: "direct main"
description:
name: simple_gesture_detector
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
sky_engine:
dependency: transitive
description: flutter
@ -676,21 +704,21 @@ packages:
name: source_gen
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.6"
version: "1.2.2"
source_helper:
dependency: transitive
description:
name: source_helper
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.3"
version: "1.3.2"
source_span:
dependency: transitive
description:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.0"
version: "1.8.2"
stack_trace:
dependency: transitive
description:
@ -704,7 +732,7 @@ packages:
name: stacked
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
version: "2.3.15"
stacked_core:
dependency: transitive
description:
@ -725,28 +753,28 @@ packages:
name: stream_transform
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.0.0"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
version: "1.1.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
version: "1.2.0"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.12"
version: "0.4.9"
timing:
dependency: transitive
description:
@ -774,14 +802,14 @@ packages:
name: url_launcher
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.7"
version: "6.1.5"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.22"
version: "6.0.17"
url_launcher_ios:
dependency: transitive
description:
@ -809,7 +837,7 @@ packages:
name: url_launcher_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
version: "2.1.0"
url_launcher_web:
dependency: transitive
description:
@ -824,13 +852,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
uuid:
dependency: transitive
description:
name: uuid
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.7"
validators:
dependency: "direct main"
description:
@ -851,7 +872,7 @@ packages:
name: watcher
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
version: "1.0.1"
web_socket_channel:
dependency: transitive
description:
@ -865,14 +886,14 @@ packages:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.2"
version: "2.7.0"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0+2"
version: "0.2.0+1"
yaml:
dependency: transitive
description:
@ -881,5 +902,5 @@ packages:
source: hosted
version: "3.1.1"
sdks:
dart: ">=2.18.6 <3.0.0"
flutter: ">=3.3.0"
dart: ">=2.17.3 <3.0.0"
flutter: ">=3.0.0"

View file

@ -11,10 +11,10 @@ description: A mobile client for FileBin.
# 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.5.0+16
version: 1.4.3+16
environment:
sdk: '>=2.18.5 <3.0.0'
sdk: '>=2.17.3 <3.0.0'
dependencies:
flutter:
@ -23,31 +23,31 @@ dependencies:
flutter_localizations:
sdk: flutter
flutter_translate: 4.0.3
provider: 6.0.5
stacked: 3.0.1
provider: 6.0.3
stacked: 2.3.15
get_it: 7.2.0
logger: 1.1.0
shared_preferences: 2.0.15
http: 0.13.5
validators: 3.0.0
flutter_linkify: 5.0.2
url_launcher: 6.1.7
url_launcher: 6.1.5
expandable: 5.0.1
share_plus: 6.3.0
file_picker: 5.2.4
share_plus: 4.0.10+1
file_picker: 5.0.1
clipboard: 0.1.3
receive_sharing_intent: 1.4.5
permission_handler: 10.2.0
package_info_plus: 3.0.2
json_annotation: 4.7.0
dynamic_color: 1.5.4
permission_handler: 10.0.0
package_info_plus: 1.4.3+1
simple_gesture_detector: 0.2.0
json_annotation: 4.6.0
dev_dependencies:
flutter_test:
sdk: flutter
build_runner: 2.3.2
built_value_generator: 8.4.2
json_serializable: 6.5.4
build_runner: 2.2.0
built_value_generator: 8.4.0
json_serializable: 6.3.1
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec