Skip to content

Commit

Permalink
Redesign mobile home page
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeDoctorDE committed Dec 30, 2024
1 parent eeea6b4 commit d4e98ef
Show file tree
Hide file tree
Showing 10 changed files with 1,398 additions and 1,253 deletions.
2 changes: 1 addition & 1 deletion app/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import 'settings/connections.dart';
import 'setup.dart' if (dart.library.js_interop) 'setup_web.dart';
import 'theme.dart';
import 'views/error.dart';
import 'views/home.dart';
import 'views/home/page.dart';
import 'views/main.dart';

const platform = MethodChannel('linwood.dev/butterfly');
Expand Down
1 change: 1 addition & 0 deletions app/lib/settings/experiments.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class ExperimentsSettingsPage extends StatelessWidget {
IconButton(
icon:
const PhosphorIcon(PhosphorIconsLight.clockCounterClockwise),
tooltip: LeapLocalizations.of(context).reset,
onPressed: () => context.read<SettingsCubit>().resetFlags(),
),
],
Expand Down
144 changes: 73 additions & 71 deletions app/lib/settings/home.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:butterfly/cubits/settings.dart';
import 'package:butterfly/main.dart';
import 'package:butterfly/settings/behaviors.dart';
import 'package:butterfly/settings/inputs/home.dart';
Expand Down Expand Up @@ -72,78 +73,79 @@ class _SettingsPageState extends State<SettingsPage> {

@override
Widget build(BuildContext context) {
return SafeArea(
child: Material(
type: widget.isDialog ? MaterialType.transparency : MaterialType.canvas,
child: LayoutBuilder(builder: (context, constraints) {
final isMobile = constraints.maxWidth < 600;

void navigateTo(SettingsView view) {
if (isMobile) {
context.push(view.path);
} else {
setState(() {
_view = view;
});
}
}

var navigation = Column(mainAxisSize: MainAxisSize.min, children: [
Header(
title: Text(AppLocalizations.of(context).settings),
leading: IconButton.outlined(
icon: const PhosphorIcon(PhosphorIconsLight.x),
onPressed: () => Navigator.of(context).pop(),
),
),
Flexible(
child: Material(
type: widget.isDialog
? MaterialType.transparency
: MaterialType.canvas,
child: ListView(
controller: _scrollController,
shrinkWrap: true,
children: [
...SettingsView.values
.where((e) => e.isEnabled)
.map((view) {
final selected = _view == view && !isMobile;
return ListTile(
leading: PhosphorIcon(view.icon(selected
? PhosphorIconsStyle.fill
: PhosphorIconsStyle.light)),
title: Text(view.getLocalizedName(context)),
onTap: () => navigateTo(view),
selected: selected,
);
}),
]),
),
)
]);
if (isMobile) {
return navigation;
}
final content = switch (_view) {
SettingsView.general => const GeneralSettingsPage(inView: true),
SettingsView.data => const DataSettingsPage(inView: true),
SettingsView.behaviors => const BehaviorsSettingsPage(inView: true),
SettingsView.inputs => const InputsSettingsPage(inView: true),
SettingsView.personalization =>
const PersonalizationSettingsPage(inView: true),
SettingsView.view => const ViewSettingsPage(inView: true),
SettingsView.connections =>
const ConnectionsSettingsPage(inView: true),
SettingsView.experiments =>
const ExperimentsSettingsPage(inView: true),
};
return Row(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
SizedBox(width: 300, child: navigation),
Expanded(child: content),
]);
}),
final size = MediaQuery.sizeOf(context);
final isMobile = size.width < LeapBreakpoints.compact;
final body = _buildBody(context, isMobile);
if (widget.isDialog) {
return body;
}
return Scaffold(
appBar: WindowTitleBar<SettingsCubit, ButterflySettings>(
title: Text(AppLocalizations.of(context).settings),
),
body: body,
);
}

Widget _buildBody(BuildContext context, bool isMobile) {
void navigateTo(SettingsView view) {
if (isMobile) {
context.push(view.path);
} else {
setState(() {
_view = view;
});
}
}

var navigation = Column(mainAxisSize: MainAxisSize.min, children: [
if (widget.isDialog)
Header(
title: Text(AppLocalizations.of(context).settings),
leading: IconButton.outlined(
icon: const PhosphorIcon(PhosphorIconsLight.x),
onPressed: () => Navigator.of(context).pop(),
),
),
Flexible(
child: Material(
type: MaterialType.transparency,
child: ListView(
controller: _scrollController,
shrinkWrap: true,
children: [
...SettingsView.values.where((e) => e.isEnabled).map((view) {
final selected = _view == view && !isMobile;
return ListTile(
leading: PhosphorIcon(view.icon(selected
? PhosphorIconsStyle.fill
: PhosphorIconsStyle.light)),
title: Text(view.getLocalizedName(context)),
onTap: () => navigateTo(view),
selected: selected,
);
}),
]),
),
)
]);
if (isMobile) {
return navigation;
}
final content = switch (_view) {
SettingsView.general => const GeneralSettingsPage(inView: true),
SettingsView.data => const DataSettingsPage(inView: true),
SettingsView.behaviors => const BehaviorsSettingsPage(inView: true),
SettingsView.inputs => const InputsSettingsPage(inView: true),
SettingsView.personalization =>
const PersonalizationSettingsPage(inView: true),
SettingsView.view => const ViewSettingsPage(inView: true),
SettingsView.connections => const ConnectionsSettingsPage(inView: true),
SettingsView.experiments => const ExperimentsSettingsPage(inView: true),
};
return Row(crossAxisAlignment: CrossAxisAlignment.stretch, children: [
SizedBox(width: 300, child: navigation),
Expanded(child: content),
]);
}
}
103 changes: 103 additions & 0 deletions app/lib/views/files/recently.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import 'dart:typed_data';

import 'package:butterfly/api/file_system.dart';
import 'package:butterfly/api/open.dart';
import 'package:butterfly/cubits/settings.dart';
import 'package:butterfly/views/files/card.dart';
import 'package:butterfly_api/butterfly_api.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:lw_file_system/lw_file_system.dart';

class RecentFilesView extends StatefulWidget {
final bool replace, asGrid;
const RecentFilesView({
super.key,
required this.replace,
this.asGrid = false,
});

@override
State<RecentFilesView> createState() => _RecentFilesViewState();
}

class _RecentFilesViewState extends State<RecentFilesView> {
late Stream<List<FileSystemEntity<NoteFile>>> _stream;
late final ButterflyFileSystem _fileSystem;
final ScrollController _recentScrollController = ScrollController();

@override
void initState() {
super.initState();
_fileSystem = context.read<ButterflyFileSystem>();
_setStream(context.read<SettingsCubit>().state);
}

@override
void dispose() {
_recentScrollController.dispose();
super.dispose();
}

void _setStream(ButterflySettings settings) =>
_stream = GeneralDirectoryFileSystem.fetchAssetsGlobalSync(
settings.history, _fileSystem.buildAllDocumentSystems());

Widget _getItem(FileSystemEntity<NoteFile> entity) {
FileMetadata? metadata;
Uint8List? thumbnail;
if (entity is FileSystemFile<NoteFile>) {
final data = entity.data?.load();
metadata = data?.getMetadata();
thumbnail = data?.getThumbnail();
}
return AssetCard(
metadata: metadata,
thumbnail: thumbnail,
name: entity.location.identifier,
height: double.infinity,
onTap: () => openFile(context, widget.replace, entity.location),
);
}

@override
Widget build(BuildContext context) {
return BlocListener<SettingsCubit, ButterflySettings>(
listenWhen: (previous, current) => previous.history != current.history,
listener: (_, state) => setState(() {
_setStream(state);
}),
child: StreamBuilder<List<FileSystemEntity<NoteFile>>>(
stream: _stream,
builder: (context, snapshot) {
final files = snapshot.data ?? [];
if (files.isEmpty) {
return Container();
}
return widget.asGrid
? GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
childAspectRatio: kThumbnailRatio,
crossAxisCount: 2,
),
itemCount: files.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => _getItem(files[index]),
)
: SizedBox(
height: 128,
child: Scrollbar(
controller: _recentScrollController,
child: ListView.builder(
controller: _recentScrollController,
scrollDirection: Axis.horizontal,
itemCount: files.length,
itemBuilder: (context, index) => _getItem(files[index]),
),
),
);
}),
);
}
}
Loading

0 comments on commit d4e98ef

Please sign in to comment.