Files
noo/lib/models/nextcloud_item.dart
T
ayushyaandClaude Sonnet 5 d68cc43368 Add Trash/Shares/Recent tabs, file sharing, Details sheet, and rebrand to Noo
Major additions since the initial rebuild:
- New tabs: Trash, Shares, Recent, configurable tab visibility/order/default
- Nextcloud sharing: search users/teams, internal link, email shares,
  public links, "others with access" - in its own Share bottom sheet
- Details bottom sheet (Info/Versions/Activity) with a persistent peek
  panel in the media viewer, reachable from selection, swipe, and the
  media viewer
- Files/Photos: tap-and-hold multi-select with a sticky selection toolbar,
  swipe actions (favorite/delete/share), sticky sort/filter controls,
  list/grid views, breadcrumb chips, whole-account Photos view
- Media viewer: pinch/double-tap zoom on images, predictive-back support,
  fixed PDF zoom-out floor
- Settings: Material You theming incl. AMOLED black, configurable bottom
  bar tabs, swipe actions, media seek bar style, and folder-listing cache
  policy (never/periodic/manual) to cut down on refetching
- Login flow moved to an in-app Chrome Custom Tab with retry-tolerant
  polling
- Replaced ad hoc widgets with native Material 3 equivalents (toggle
  IconButtons, SliverAppBar selection toolbar, SearchBar, drag handles)
- Rebrand: app renamed to Noo throughout, package id -> dev.ayushya.noo,
  new adaptive launcher icon

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 22:44:42 -04:00

181 lines
4.8 KiB
Dart

import 'package:flutter/material.dart';
enum NextcloudItemType { file, folder, image, video, document, audio, archive }
class NextcloudItem {
final String id;
final String name;
final String path;
final NextcloudItemType type;
final int size; // in bytes
final DateTime lastModified;
final DateTime dateCreated;
final bool isFavorite;
final String? mimeType;
final String? etag;
final String? previewUrl;
final int? imageWidth;
final int? imageHeight;
final String? mountType;
/// Trash-bin items only: the folder path the item was deleted from, and
/// when it was deleted. Null for items fetched from a regular directory.
final String? originalLocation;
final DateTime? deletedAt;
const NextcloudItem({
required this.id,
required this.name,
required this.path,
required this.type,
required this.size,
required this.lastModified,
DateTime? dateCreated,
this.isFavorite = false,
this.mimeType,
this.etag,
this.previewUrl,
this.imageWidth,
this.imageHeight,
this.mountType,
this.originalLocation,
this.deletedAt,
}) : dateCreated = dateCreated ?? lastModified;
bool get isFolder => type == NextcloudItemType.folder;
bool get isMedia =>
type == NextcloudItemType.image || type == NextcloudItemType.video;
bool get isExternalStorage => mountType == 'external';
NextcloudItem copyWith({
String? id,
String? name,
String? path,
NextcloudItemType? type,
int? size,
DateTime? lastModified,
DateTime? dateCreated,
bool? isFavorite,
String? mimeType,
String? etag,
String? previewUrl,
int? imageWidth,
int? imageHeight,
String? mountType,
String? originalLocation,
DateTime? deletedAt,
}) {
return NextcloudItem(
id: id ?? this.id,
name: name ?? this.name,
path: path ?? this.path,
type: type ?? this.type,
size: size ?? this.size,
lastModified: lastModified ?? this.lastModified,
dateCreated: dateCreated ?? this.dateCreated,
isFavorite: isFavorite ?? this.isFavorite,
mimeType: mimeType ?? this.mimeType,
etag: etag ?? this.etag,
previewUrl: previewUrl ?? this.previewUrl,
imageWidth: imageWidth ?? this.imageWidth,
imageHeight: imageHeight ?? this.imageHeight,
mountType: mountType ?? this.mountType,
originalLocation: originalLocation ?? this.originalLocation,
deletedAt: deletedAt ?? this.deletedAt,
);
}
static NextcloudItemType deduceType(
String path,
bool isCollection,
String? mime,
) {
if (isCollection) return NextcloudItemType.folder;
final lower = path.toLowerCase();
if (mime?.startsWith('image/') == true ||
lower.endsWith('.jpg') ||
lower.endsWith('.jpeg') ||
lower.endsWith('.png') ||
lower.endsWith('.webp') ||
lower.endsWith('.gif') ||
lower.endsWith('.heic')) {
return NextcloudItemType.image;
}
if (mime?.startsWith('video/') == true ||
lower.endsWith('.mp4') ||
lower.endsWith('.mov') ||
lower.endsWith('.mkv') ||
lower.endsWith('.webm')) {
return NextcloudItemType.video;
}
if (mime?.startsWith('audio/') == true ||
lower.endsWith('.mp3') ||
lower.endsWith('.flac') ||
lower.endsWith('.wav') ||
lower.endsWith('.ogg')) {
return NextcloudItemType.audio;
}
if (lower.endsWith('.pdf') ||
lower.endsWith('.txt') ||
lower.endsWith('.md') ||
lower.endsWith('.docx') ||
lower.endsWith('.xlsx')) {
return NextcloudItemType.document;
}
if (lower.endsWith('.zip') ||
lower.endsWith('.tar') ||
lower.endsWith('.gz') ||
lower.endsWith('.7z')) {
return NextcloudItemType.archive;
}
return NextcloudItemType.file;
}
}
class NextcloudUserQuota {
final int usedBytes;
final int totalBytes;
final double usagePercentage;
final String userName;
final String email;
final String serverVersion;
const NextcloudUserQuota({
required this.usedBytes,
required this.totalBytes,
required this.usagePercentage,
required this.userName,
required this.email,
required this.serverVersion,
});
factory NextcloudUserQuota.demo() {
return const NextcloudUserQuota(
usedBytes: 48500000000, // ~45.17 GB
totalBytes: 107374182400, // 100 GB
usagePercentage: 0.4517,
userName: 'Ayush Admin',
email: 'ayush@cloud.internal',
serverVersion: 'Nextcloud 29.0.4 Hub 8',
);
}
}
class NextcloudActivity {
final String id;
final String title;
final String subject;
final DateTime timestamp;
final IconData icon;
final String author;
const NextcloudActivity({
required this.id,
required this.title,
required this.subject,
required this.timestamp,
required this.icon,
required this.author,
});
}