Skip to content

Commit

Permalink
feat(project): setting project icon
Browse files Browse the repository at this point in the history
  • Loading branch information
charles0122 committed Aug 31, 2024
1 parent 57bdeb1 commit 161c0c5
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 15 deletions.
38 changes: 37 additions & 1 deletion lib/src/modules/projects/components/project_list_item.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import 'package:file_selector/file_selector.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:fvm/fvm.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:sidekick/src/modules/common/utils/helpers.dart';
Expand All @@ -10,8 +13,10 @@ import '../../../components/molecules/version_install_button.dart';
import '../../releases/releases.provider.dart';
import '../../sandbox/sandbox.screen.dart';
import '../project.dto.dart';
import '../projects.provider.dart';
import 'project_actions.dart';
import 'project_release_select.dart';
import 'package:file_selector/file_selector.dart' as selector;

/// Project list item
class ProjectListItem extends ConsumerWidget {
Expand All @@ -30,6 +35,8 @@ class ProjectListItem extends ConsumerWidget {

@override
Widget build(BuildContext context, WidgetRef ref) {
final notifier = ref.watch(projectsProvider.notifier);

final cachedVersions = ref.watch(releasesStateProvider).all;

final version = ref.watch(getVersionProvider(project.pinnedVersion));
Expand Down Expand Up @@ -62,14 +69,37 @@ class ProjectListItem extends ConsumerWidget {
);
}

Future<void> handleChangeProjectIcon(Project project) async {
const XTypeGroup typeGroup = XTypeGroup(
label: 'images',
extensions: <String>['svg'],
);

final XFile? iconFile = await selector.openFile(
confirmButtonText: context.i18n('modules:projects.choose'),
acceptedTypeGroups: <XTypeGroup>[typeGroup]);
if (iconFile == null) {
// Operation was canceled by the user.
return;
}
// ignore: use_build_context_synchronously
await notifier.changeProjectIcon(context, project, iconFile);
}

return SizedBox(
height: 170,
child: Center(
child: Card(
child: Column(
children: [
ListTile(
leading: const Icon(MdiIcons.alphaPBox),
leading: project.projectIcon != ""
? SvgPicture.string(
project.projectIcon,
width: 24,
height: 24,
)
: const Icon(MdiIcons.alphaPBox),
title: Subheading(project.name),
trailing: ProjectActions(project),
),
Expand Down Expand Up @@ -122,6 +152,12 @@ class ProjectListItem extends ConsumerWidget {
),
),
const Spacer(),

/// TODO: Need Update UI
TextButton(
onPressed: () => handleChangeProjectIcon(project),
child: Text("Change Icon"),
),
versionSelect
? Row(
children: [
Expand Down
26 changes: 17 additions & 9 deletions lib/src/modules/projects/project.dto.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class FlutterProject extends Project {
required Directory projectDir,
required this.pubspec,
this.invalid = false,
this.projectIcon = "",
}) : super(
name: name,
config: config,
Expand All @@ -27,12 +28,14 @@ class FlutterProject extends Project {
final bool invalid;

/// Create Flutter project from project
factory FlutterProject.fromProject(Project project, Pubspec pubspec) {
factory FlutterProject.fromProject(Project project, Pubspec pubspec,
{String projectIcon = ""}) {
return FlutterProject._(
name: project.name ?? pubspec.name,
config: project.config,
projectDir: project.projectDir,
pubspec: pubspec,
projectIcon: projectIcon,
);
}

Expand All @@ -44,6 +47,7 @@ class FlutterProject extends Project {
projectDir: project.projectDir,
pubspec: null,
invalid: true,
projectIcon: "",
);
}

Expand All @@ -54,13 +58,17 @@ class FlutterProject extends Project {
String get description {
return pubspec?.description ?? '';
}

/// Project Icon Raw String Data
late String projectIcon;
}

/// Ref to project path
class ProjectRef {
/// Constructor
const ProjectRef({
ProjectRef({
required this.name,
required this.projectIcon,
required this.path,
});

Expand All @@ -70,20 +78,20 @@ class ProjectRef {
/// Project path
final String path;

/// Project Icon
final String projectIcon;

/// Creates a project path from map
factory ProjectRef.fromMap(Map<String, String> map) {
return ProjectRef(
name: map['name'] ?? '',
path: map['path'] ?? '',
);
name: map['name'] ?? '',
path: map['path'] ?? '',
projectIcon: map['projectIcon'] ?? '');
}

/// Returns project path as a map
Map<String, String> toMap() {
return {
'name': name,
'path': path,
};
return {'name': name, 'path': path, 'projectIcon': projectIcon};
}
}

Expand Down
26 changes: 25 additions & 1 deletion lib/src/modules/projects/projects.provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
// ignore_for_file: top_level_function_literal_block

import 'dart:async';
import 'dart:developer';
import 'dart:io';

import 'package:file_selector/file_selector.dart';
import 'package:flutter/widgets.dart';
import 'package:fvm/fvm.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
Expand Down Expand Up @@ -80,7 +82,8 @@ class ProjectsStateNotifier extends StateNotifier<List<FlutterProject>> {
Future<void> addProject(BuildContext context, String path) async {
final project = await FVMClient.getProjectByDirectory(Directory(path));
if (project.isFlutterProject) {
final ref = ProjectRef(name: path.split('/').last, path: path);
final ref =
ProjectRef(name: path.split('/').last, path: path, projectIcon: "");
await ProjectsService.box.put(path, ref);
await load();
} else {
Expand All @@ -89,6 +92,27 @@ class ProjectsStateNotifier extends StateNotifier<List<FlutterProject>> {
}
}

/// Adds a project
Future<void> changeProjectIcon(
BuildContext context, Project project, XFile file) async {
// TODO: File should handle
// 1. handle svg size
// 2. handle svg unsupported element https://pub.dev/packages/flutter_svg#precompiling-and-optimizing-svgs
if (project.isFlutterProject) {
project as FlutterProject;
await ProjectsService.box.put(
project.projectDir.path,
ProjectRef(
name: project.name,
path: project.projectDir.path,
projectIcon: await file.readAsString()));
await load();
} else {
// ignore: use_build_context_synchronously
notify(context.i18n('modules:projects.notAFlutterProject'));
}
}

/// Removes a project
void removeProject(Directory projectDir) {
ProjectsService.box.delete(projectDir.path);
Expand Down
15 changes: 11 additions & 4 deletions lib/src/modules/projects/projects.service.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:developer';
import 'dart:io';

import 'package:collection/collection.dart';
Expand Down Expand Up @@ -35,24 +36,30 @@ class ProjectsService {
final projects = await FVMClient.fetchProjects(directories);

/// Check if its flutter project
final projectsWithFlutter = projects.where((p) => p.isFlutterProject);
final Iterable<Project> projectsWithFlutter =
projects.where((p) => p.isFlutterProject);

/// Return flutter projects
final flutterProjects = projectsWithFlutter.map((project) async {
final pubspecFile = project.pubspecFile;
if (box.get(project.projectDir.path) == null) {
await box.delete(project.projectDir.path);
}

final pubspecFile = project.pubspecFile;
if (await pubspecFile.exists()) {
final yaml = await pubspecFile.readAsString();
final pubspec = Pubspec.parse(yaml);

return FlutterProject.fromProject(project, pubspec);
log(project.projectDir.path);
return FlutterProject.fromProject(project, pubspec,
projectIcon: box.get(project.projectDir.path)!.projectIcon);
} else {
/// If it does not exist should be removed
await box.delete(project.projectDir.path);
}
});

final results = await Future.wait(flutterProjects);
log(results.length.toString());
return results.whereNotNull();
}

Expand Down
40 changes: 40 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.2.1"
flutter_svg:
dependency: "direct main"
description:
name: flutter_svg
sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.10+1"
flutter_test:
dependency: "direct dev"
description: flutter
Expand Down Expand Up @@ -852,6 +860,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.9.0"
path_parsing:
dependency: transitive
description:
name: path_parsing
sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.1"
path_provider:
dependency: "direct main"
description:
Expand Down Expand Up @@ -1281,6 +1297,30 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.2"
vector_graphics:
dependency: transitive
description:
name: vector_graphics
sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.11+1"
vector_graphics_codec:
dependency: transitive
description:
name: vector_graphics_codec
sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.11+1"
vector_graphics_compiler:
dependency: transitive
description:
name: vector_graphics_compiler
sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.11+1"
vector_math:
dependency: transitive
description:
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dependencies:
sdk: flutter
flutter_spinkit: ^5.0.0
fvm: ^2.4.1
flutter_svg: ^2.0.10+1
google_fonts: ^6.2.1
hive: ^2.0.4
hive_flutter: ^1.0.0
Expand Down

0 comments on commit 161c0c5

Please sign in to comment.