@shaxpir/duiduidui-models 1.5.14 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -72,4 +72,52 @@ export declare const Condition: {
72
72
  intermediate: () => DifficultyCondition;
73
73
  advanced: () => DifficultyCondition;
74
74
  expert: () => DifficultyCondition;
75
+ /**
76
+ * Check if starred condition is required (in 'all' section)
77
+ */
78
+ requiresStarred: (filters?: ConditionFilters) => boolean;
79
+ /**
80
+ * Check if starred condition is optional (in 'any' section)
81
+ */
82
+ allowsStarred: (filters?: ConditionFilters) => boolean;
83
+ /**
84
+ * Check if starred condition is excluded (in 'none' section)
85
+ */
86
+ excludesStarred: (filters?: ConditionFilters) => boolean;
87
+ /**
88
+ * Check if starred condition exists anywhere in filters
89
+ */
90
+ hasStarred: (filters?: ConditionFilters) => boolean;
91
+ /**
92
+ * Check if a specific tag is required (in 'all' section)
93
+ */
94
+ requiresTag: (filters: ConditionFilters | undefined, tag: string) => boolean;
95
+ /**
96
+ * Check if a specific tag is optional (in 'any' section)
97
+ */
98
+ allowsTag: (filters: ConditionFilters | undefined, tag: string) => boolean;
99
+ /**
100
+ * Check if a specific tag is excluded (in 'none' section)
101
+ */
102
+ excludesTag: (filters: ConditionFilters | undefined, tag: string) => boolean;
103
+ /**
104
+ * Check if a specific grade is required (in 'all' section)
105
+ */
106
+ requiresGrade: (filters: ConditionFilters | undefined, grade: "A" | "B" | "C" | "D" | "F") => boolean;
107
+ /**
108
+ * Check if any condition of a specific type exists in filters
109
+ */
110
+ hasConditionType: (filters: ConditionFilters | undefined, type: string) => boolean;
111
+ /**
112
+ * Validate filters for logical inconsistencies
113
+ * Returns an array of error messages, empty if valid
114
+ */
115
+ validate: (filters?: ConditionFilters) => string[];
116
+ hasStarredInAll: (filters?: ConditionFilters) => boolean;
117
+ hasStarredInAny: (filters?: ConditionFilters) => boolean;
118
+ hasStarredInNone: (filters?: ConditionFilters) => boolean;
119
+ hasTagInAll: (filters: ConditionFilters | undefined, tag: string) => boolean;
120
+ hasTagInAny: (filters: ConditionFilters | undefined, tag: string) => boolean;
121
+ hasTagInNone: (filters: ConditionFilters | undefined, tag: string) => boolean;
122
+ hasGradeInAll: (filters: ConditionFilters | undefined, grade: "A" | "B" | "C" | "D" | "F") => boolean;
75
123
  };
@@ -37,5 +37,106 @@ exports.Condition = {
37
37
  elementary: () => ({ type: 'difficulty', min: 100, max: 500 }), // Easy
38
38
  intermediate: () => ({ type: 'difficulty', min: 500, max: 1500 }), // Medium
39
39
  advanced: () => ({ type: 'difficulty', min: 1500, max: 3000 }), // Hard
40
- expert: () => ({ type: 'difficulty', min: 3000 }) // Very hard
40
+ expert: () => ({ type: 'difficulty', min: 3000 }), // Very hard
41
+ // Helper methods to check if conditions are present in filters
42
+ /**
43
+ * Check if starred condition is required (in 'all' section)
44
+ */
45
+ requiresStarred: (filters) => {
46
+ return !!(filters?.all?.some(c => c.type === 'starred' && c.value === true));
47
+ },
48
+ /**
49
+ * Check if starred condition is optional (in 'any' section)
50
+ */
51
+ allowsStarred: (filters) => {
52
+ return !!(filters?.any?.some(c => c.type === 'starred' && c.value === true));
53
+ },
54
+ /**
55
+ * Check if starred condition is excluded (in 'none' section)
56
+ */
57
+ excludesStarred: (filters) => {
58
+ return !!(filters?.none?.some(c => c.type === 'starred' && c.value === true));
59
+ },
60
+ /**
61
+ * Check if starred condition exists anywhere in filters
62
+ */
63
+ hasStarred: (filters) => {
64
+ return exports.Condition.requiresStarred(filters) ||
65
+ exports.Condition.allowsStarred(filters) ||
66
+ exports.Condition.excludesStarred(filters);
67
+ },
68
+ /**
69
+ * Check if a specific tag is required (in 'all' section)
70
+ */
71
+ requiresTag: (filters, tag) => {
72
+ return !!(filters?.all?.some(c => c.type === 'tag' && c.tag === tag));
73
+ },
74
+ /**
75
+ * Check if a specific tag is optional (in 'any' section)
76
+ */
77
+ allowsTag: (filters, tag) => {
78
+ return !!(filters?.any?.some(c => c.type === 'tag' && c.tag === tag));
79
+ },
80
+ /**
81
+ * Check if a specific tag is excluded (in 'none' section)
82
+ */
83
+ excludesTag: (filters, tag) => {
84
+ return !!(filters?.none?.some(c => c.type === 'tag' && c.tag === tag));
85
+ },
86
+ /**
87
+ * Check if a specific grade is required (in 'all' section)
88
+ */
89
+ requiresGrade: (filters, grade) => {
90
+ return !!(filters?.all?.some(c => c.type === 'grade' && c.grade === grade));
91
+ },
92
+ /**
93
+ * Check if any condition of a specific type exists in filters
94
+ */
95
+ hasConditionType: (filters, type) => {
96
+ return !!(filters?.all?.some(c => c.type === type) ||
97
+ filters?.any?.some(c => c.type === type) ||
98
+ filters?.none?.some(c => c.type === type));
99
+ },
100
+ /**
101
+ * Validate filters for logical inconsistencies
102
+ * Returns an array of error messages, empty if valid
103
+ */
104
+ validate: (filters) => {
105
+ if (!filters)
106
+ return [];
107
+ const errors = [];
108
+ // Check for contradictory starred conditions
109
+ if (exports.Condition.requiresStarred(filters) && exports.Condition.excludesStarred(filters)) {
110
+ errors.push('Cannot require starred items and exclude starred items at the same time');
111
+ }
112
+ // Check for contradictory tags
113
+ const allTags = filters.all?.filter(c => c.type === 'tag').map(c => c.tag) || [];
114
+ const noneTags = filters.none?.filter(c => c.type === 'tag').map(c => c.tag) || [];
115
+ allTags.forEach(tag => {
116
+ if (noneTags.includes(tag)) {
117
+ errors.push(`Tag "${tag}" cannot be both required and excluded`);
118
+ }
119
+ });
120
+ // Check for contradictory grades
121
+ const allGrades = filters.all?.filter(c => c.type === 'grade').map(c => c.grade) || [];
122
+ const noneGrades = filters.none?.filter(c => c.type === 'grade').map(c => c.grade) || [];
123
+ allGrades.forEach(grade => {
124
+ if (noneGrades.includes(grade)) {
125
+ errors.push(`Grade "${grade}" cannot be both required and excluded`);
126
+ }
127
+ });
128
+ // Check for multiple required grades (can only have one grade at a time)
129
+ if (allGrades.length > 1) {
130
+ errors.push(`Cannot require multiple grades: ${allGrades.join(', ')} - an item can only have one grade`);
131
+ }
132
+ return errors;
133
+ },
134
+ // Backward compatibility aliases (deprecated - use requiresStarred/allowsStarred/excludesStarred instead)
135
+ hasStarredInAll: (filters) => exports.Condition.requiresStarred(filters),
136
+ hasStarredInAny: (filters) => exports.Condition.allowsStarred(filters),
137
+ hasStarredInNone: (filters) => exports.Condition.excludesStarred(filters),
138
+ hasTagInAll: (filters, tag) => exports.Condition.requiresTag(filters, tag),
139
+ hasTagInAny: (filters, tag) => exports.Condition.allowsTag(filters, tag),
140
+ hasTagInNone: (filters, tag) => exports.Condition.excludesTag(filters, tag),
141
+ hasGradeInAll: (filters, grade) => exports.Condition.requiresGrade(filters, grade)
41
142
  };
@@ -4,7 +4,7 @@ import { ShareSync } from '../repo';
4
4
  import { BillingPayload } from './Billing';
5
5
  import { ContentKind } from './ContentKind';
6
6
  import { DevicePayload } from './Device';
7
- import { MediaPayload } from './Media';
7
+ import { ImagePayload } from './Image';
8
8
  import { MetricPayload } from './Metric';
9
9
  import { Model } from './Model';
10
10
  import { ProfilePayload } from "./Profile";
@@ -36,7 +36,7 @@ export interface ContentMeta {
36
36
  created_at: MultiTime;
37
37
  updated_at: MultiTime;
38
38
  }
39
- export type ContentPayload = BillingPayload | DevicePayload | MediaPayload | MetricPayload | ProfilePayload | ProgressPayload | SessionPayload | TermPayload | UserPayload | WorkspacePayload;
39
+ export type ContentPayload = BillingPayload | DevicePayload | ImagePayload | MetricPayload | ProfilePayload | ProgressPayload | SessionPayload | TermPayload | UserPayload | WorkspacePayload;
40
40
  export declare abstract class Content extends Model {
41
41
  static ID_LENGTH: number;
42
42
  constructor(doc: Doc, shouldAcquire: boolean, shareSync: ShareSync);
@@ -7,7 +7,7 @@ export declare enum ContentKind {
7
7
  SESSION = "session",
8
8
  TERM = "term",
9
9
  USER = "user",
10
- MEDIA = "media",
10
+ IMAGE = "image",
11
11
  WORKSPACE = "workspace",
12
12
  MANIFEST = "manifest"
13
13
  }
@@ -13,7 +13,7 @@ var ContentKind;
13
13
  ContentKind["SESSION"] = "session";
14
14
  ContentKind["TERM"] = "term";
15
15
  ContentKind["USER"] = "user";
16
- ContentKind["MEDIA"] = "media";
16
+ ContentKind["IMAGE"] = "image";
17
17
  ContentKind["WORKSPACE"] = "workspace";
18
18
  // These are used in the ShareDB system, but for internal bookkeeping, not for Content subclasses.
19
19
  ContentKind["MANIFEST"] = "manifest";
@@ -6,27 +6,42 @@ import { ConditionFilters } from './Condition';
6
6
  export interface LastSync {
7
7
  at_utc_time: CompactDateTime | null;
8
8
  }
9
- export interface AudioDownloadQueueItem {
10
- text: string;
9
+ interface BaseQueueItem {
11
10
  added_at: CompactDateTime;
12
11
  retry_count: number;
13
12
  next_retry_at?: CompactDateTime;
14
13
  last_error?: string;
15
14
  }
15
+ export interface AudioDownloadQueueItem extends BaseQueueItem {
16
+ type: 'audio';
17
+ text: string;
18
+ }
19
+ export interface ImageDownloadQueueItem extends BaseQueueItem {
20
+ type: 'image';
21
+ image_id: ContentId;
22
+ }
23
+ export type DownloadQueueItem = AudioDownloadQueueItem | ImageDownloadQueueItem;
24
+ export interface ImageUploadQueueItem extends BaseQueueItem {
25
+ type: 'image';
26
+ image_id: ContentId;
27
+ }
28
+ export type UploadQueueItem = ImageUploadQueueItem;
16
29
  export interface DevicePayload {
17
30
  last_sync?: LastSync;
18
31
  chinese_font?: string;
19
32
  raw_search_text?: string;
20
33
  star_filter?: boolean;
21
34
  conditions?: ConditionFilters;
22
- audio_download_queue?: AudioDownloadQueueItem[];
35
+ download_queue?: DownloadQueueItem[];
36
+ upload_queue?: UploadQueueItem[];
23
37
  }
24
38
  export interface DeviceBody extends ContentBody {
25
39
  meta: ContentMeta;
26
40
  payload: DevicePayload;
27
41
  }
28
42
  export declare class Device extends Content {
29
- private _audioDownloadQueueView;
43
+ private _downloadQueueView;
44
+ private _uploadQueueView;
30
45
  static create(userId: ContentId, deviceId: ContentId): Device;
31
46
  constructor(doc: Doc, shouldAcquire: boolean, shareSync: ShareSync);
32
47
  get payload(): DevicePayload;
@@ -34,9 +49,19 @@ export declare class Device extends Content {
34
49
  setLastSyncAtUtcTime(value: CompactDateTime): void;
35
50
  get chineseFont(): string;
36
51
  setChineseFont(value: string): void;
37
- get audioDownloadQueue(): AudioDownloadQueueItem[];
38
- get audioDownloadQueueLength(): number;
39
- addToAudioDownloadQueue(text: string): void;
40
- removeFromAudioDownloadQueue(text: string): void;
41
- updateAudioDownloadQueueItem(text: string, updates: Partial<AudioDownloadQueueItem>): void;
52
+ get downloadQueue(): DownloadQueueItem[];
53
+ get downloadQueueLength(): number;
54
+ addToDownloadQueue(item: AudioDownloadQueueItem | ImageDownloadQueueItem): void;
55
+ removeFromDownloadQueue(predicate: (item: DownloadQueueItem) => boolean): void;
56
+ updateDownloadQueueItem(predicate: (item: DownloadQueueItem) => boolean, updates: Partial<BaseQueueItem>): void;
57
+ addAudioToDownloadQueue(text: string): void;
58
+ removeAudioFromDownloadQueue(text: string): void;
59
+ get uploadQueue(): UploadQueueItem[];
60
+ get uploadQueueLength(): number;
61
+ addToUploadQueue(item: UploadQueueItem): void;
62
+ removeFromUploadQueue(predicate: (item: UploadQueueItem) => boolean): void;
63
+ updateUploadQueueItem(predicate: (item: UploadQueueItem) => boolean, updates: Partial<BaseQueueItem>): void;
64
+ addImageToUploadQueue(imageId: ContentId): void;
65
+ removeImageFromUploadQueue(imageId: ContentId): void;
42
66
  }
67
+ export {};
@@ -21,13 +21,15 @@ class Device extends Content_1.Content {
21
21
  },
22
22
  payload: {
23
23
  last_sync: { at_utc_time: null },
24
- audio_download_queue: []
24
+ download_queue: [],
25
+ upload_queue: []
25
26
  }
26
27
  });
27
28
  }
28
29
  constructor(doc, shouldAcquire, shareSync) {
29
30
  super(doc, shouldAcquire, shareSync);
30
- this._audioDownloadQueueView = new ArrayView_1.ArrayView(this, ['payload', 'audio_download_queue']);
31
+ this._downloadQueueView = new ArrayView_1.ArrayView(this, ['payload', 'download_queue']);
32
+ this._uploadQueueView = new ArrayView_1.ArrayView(this, ['payload', 'upload_queue']);
31
33
  }
32
34
  get payload() {
33
35
  this.checkDisposed("Device.payload");
@@ -57,50 +59,120 @@ class Device extends Content_1.Content {
57
59
  batch.commit();
58
60
  }
59
61
  }
60
- get audioDownloadQueue() {
61
- this.checkDisposed("Device.audioDownloadQueue");
62
- return this._audioDownloadQueueView.values;
62
+ // Download Queue Methods
63
+ get downloadQueue() {
64
+ this.checkDisposed("Device.downloadQueue");
65
+ return this._downloadQueueView.values;
63
66
  }
64
- get audioDownloadQueueLength() {
65
- this.checkDisposed("Device.audioDownloadQueueLength");
66
- return this._audioDownloadQueueView.length;
67
+ get downloadQueueLength() {
68
+ this.checkDisposed("Device.downloadQueueLength");
69
+ return this._downloadQueueView.length;
67
70
  }
68
- addToAudioDownloadQueue(text) {
69
- this.checkDisposed("Device.addToAudioDownloadQueue");
71
+ addToDownloadQueue(item) {
72
+ this.checkDisposed("Device.addToDownloadQueue");
70
73
  // Check if item already exists in queue
71
- const existingIndex = this._audioDownloadQueueView.values.findIndex(item => item.text === text);
74
+ const existingIndex = this._downloadQueueView.values.findIndex(queueItem => {
75
+ if (queueItem.type === 'audio' && item.type === 'audio') {
76
+ return queueItem.text === item.text;
77
+ }
78
+ else if (queueItem.type === 'image' && item.type === 'image') {
79
+ return queueItem.image_id === item.image_id;
80
+ }
81
+ return false;
82
+ });
72
83
  if (existingIndex !== -1) {
73
- console.log(`Audio download already queued for: ${text}`);
84
+ console.log(`Download already queued for: ${item.type}`, item);
74
85
  return;
75
86
  }
87
+ this._downloadQueueView.push(item);
88
+ console.log(`Added to download queue: ${item.type}`, item);
89
+ }
90
+ removeFromDownloadQueue(predicate) {
91
+ this.checkDisposed("Device.removeFromDownloadQueue");
92
+ const itemIndex = this._downloadQueueView.values.findIndex(predicate);
93
+ if (itemIndex !== -1) {
94
+ this._downloadQueueView.removeAt(itemIndex);
95
+ console.log(`Removed from download queue at index ${itemIndex}`);
96
+ }
97
+ }
98
+ updateDownloadQueueItem(predicate, updates) {
99
+ this.checkDisposed("Device.updateDownloadQueueItem");
100
+ const itemIndex = this._downloadQueueView.values.findIndex(predicate);
101
+ if (itemIndex !== -1) {
102
+ for (const [key, value] of Object.entries(updates)) {
103
+ this._downloadQueueView.setObjectValueAtIndex(itemIndex, key, value);
104
+ }
105
+ console.log(`Updated download queue item at index ${itemIndex}`, updates);
106
+ }
107
+ }
108
+ // Convenience methods for audio downloads (backward compatibility)
109
+ addAudioToDownloadQueue(text) {
76
110
  const now = shaxpir_common_1.ClockService.getClock().utc();
77
- const newItem = {
111
+ this.addToDownloadQueue({
112
+ type: 'audio',
78
113
  text,
79
114
  added_at: now,
80
115
  retry_count: 0
81
- };
82
- this._audioDownloadQueueView.push(newItem);
83
- console.log(`Added to audio download queue: ${text}`);
84
- }
85
- removeFromAudioDownloadQueue(text) {
86
- this.checkDisposed("Device.removeFromAudioDownloadQueue");
87
- // Find the item index
88
- const itemIndex = this._audioDownloadQueueView.values.findIndex(item => item.text === text);
116
+ });
117
+ }
118
+ removeAudioFromDownloadQueue(text) {
119
+ this.removeFromDownloadQueue(item => item.type === 'audio' && item.text === text);
120
+ }
121
+ // Upload Queue Methods
122
+ get uploadQueue() {
123
+ this.checkDisposed("Device.uploadQueue");
124
+ return this._uploadQueueView.values;
125
+ }
126
+ get uploadQueueLength() {
127
+ this.checkDisposed("Device.uploadQueueLength");
128
+ return this._uploadQueueView.length;
129
+ }
130
+ addToUploadQueue(item) {
131
+ this.checkDisposed("Device.addToUploadQueue");
132
+ // Check if item already exists in queue
133
+ const existingIndex = this._uploadQueueView.values.findIndex(queueItem => {
134
+ if (queueItem.type === 'image' && item.type === 'image') {
135
+ return queueItem.image_id === item.image_id;
136
+ }
137
+ return false;
138
+ });
139
+ if (existingIndex !== -1) {
140
+ console.log(`Upload already queued for: ${item.type}`, item);
141
+ return;
142
+ }
143
+ this._uploadQueueView.push(item);
144
+ console.log(`Added to upload queue: ${item.type}`, item);
145
+ }
146
+ removeFromUploadQueue(predicate) {
147
+ this.checkDisposed("Device.removeFromUploadQueue");
148
+ const itemIndex = this._uploadQueueView.values.findIndex(predicate);
89
149
  if (itemIndex !== -1) {
90
- this._audioDownloadQueueView.removeAt(itemIndex);
91
- console.log(`Removed from audio download queue: ${text}`);
150
+ this._uploadQueueView.removeAt(itemIndex);
151
+ console.log(`Removed from upload queue at index ${itemIndex}`);
92
152
  }
93
153
  }
94
- updateAudioDownloadQueueItem(text, updates) {
95
- this.checkDisposed("Device.updateAudioDownloadQueueItem");
96
- const itemIndex = this._audioDownloadQueueView.values.findIndex(item => item.text === text);
154
+ updateUploadQueueItem(predicate, updates) {
155
+ this.checkDisposed("Device.updateUploadQueueItem");
156
+ const itemIndex = this._uploadQueueView.values.findIndex(predicate);
97
157
  if (itemIndex !== -1) {
98
- // Update each field in the updates object
99
158
  for (const [key, value] of Object.entries(updates)) {
100
- this._audioDownloadQueueView.setObjectValueAtIndex(itemIndex, key, value);
159
+ this._uploadQueueView.setObjectValueAtIndex(itemIndex, key, value);
101
160
  }
102
- console.log(`Updated audio download queue item: ${text}`, updates);
161
+ console.log(`Updated upload queue item at index ${itemIndex}`, updates);
103
162
  }
104
163
  }
164
+ // Convenience methods for image uploads
165
+ addImageToUploadQueue(imageId) {
166
+ const now = shaxpir_common_1.ClockService.getClock().utc();
167
+ this.addToUploadQueue({
168
+ type: 'image',
169
+ image_id: imageId,
170
+ added_at: now,
171
+ retry_count: 0
172
+ });
173
+ }
174
+ removeImageFromUploadQueue(imageId) {
175
+ this.removeFromUploadQueue(item => item.type === 'image' && item.image_id === imageId);
176
+ }
105
177
  }
106
178
  exports.Device = Device;
@@ -0,0 +1,31 @@
1
+ import { Doc } from '@shaxpir/sharedb/lib/client';
2
+ import { ShareSync } from '../repo';
3
+ import { Content, ContentBody, ContentId, ContentMeta } from "./Content";
4
+ export interface ImageDimensions {
5
+ width: number;
6
+ height: number;
7
+ }
8
+ export interface ImageCropping extends ImageDimensions {
9
+ offset_top: number;
10
+ offset_left: number;
11
+ }
12
+ export interface ImagePayload extends ImageDimensions {
13
+ extension: string;
14
+ bytes: number;
15
+ }
16
+ export interface ImageBody extends ContentBody {
17
+ meta: ContentMeta;
18
+ payload: ImagePayload;
19
+ }
20
+ export declare class Image extends Content {
21
+ constructor(doc: Doc, shouldAcquire: boolean, shareSync: ShareSync);
22
+ get payload(): ImagePayload;
23
+ static create(userId: ContentId, imageId: ContentId, payload: ImagePayload): Image;
24
+ get bytes(): number;
25
+ get width(): number;
26
+ get height(): number;
27
+ get extension(): string;
28
+ get mimeType(): string;
29
+ scaleToFit(boxSize: number, cropping: ImageCropping): ImageCropping;
30
+ static makeDefaultCropping(image: Image): ImageCropping;
31
+ }
@@ -1,25 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Media = void 0;
3
+ exports.Image = void 0;
4
4
  const shaxpir_common_1 = require("@shaxpir/shaxpir-common");
5
5
  const repo_1 = require("../repo");
6
6
  const Content_1 = require("./Content");
7
7
  const ContentKind_1 = require("./ContentKind");
8
- class Media extends Content_1.Content {
8
+ class Image extends Content_1.Content {
9
9
  constructor(doc, shouldAcquire, shareSync) {
10
10
  super(doc, shouldAcquire, shareSync);
11
11
  }
12
12
  get payload() {
13
- this.checkDisposed("Media.payload");
13
+ this.checkDisposed("Image.payload");
14
14
  return this.doc.data.payload;
15
15
  }
16
- static create(userId, mediaId, payload) {
16
+ static create(userId, imageId, payload) {
17
17
  const now = shaxpir_common_1.ClockService.getClock().now();
18
18
  return repo_1.ShareSyncFactory.get().createContent({
19
19
  meta: {
20
- ref: mediaId,
21
- kind: ContentKind_1.ContentKind.MEDIA,
22
- id: mediaId,
20
+ ref: imageId,
21
+ kind: ContentKind_1.ContentKind.IMAGE,
22
+ id: imageId,
23
23
  owner: userId,
24
24
  created_at: now,
25
25
  updated_at: now
@@ -28,23 +28,23 @@ class Media extends Content_1.Content {
28
28
  });
29
29
  }
30
30
  get bytes() {
31
- this.checkDisposed("Media.bytes");
31
+ this.checkDisposed("Image.bytes");
32
32
  return this.payload.bytes;
33
33
  }
34
34
  get width() {
35
- this.checkDisposed("Media.width");
35
+ this.checkDisposed("Image.width");
36
36
  return this.payload.width;
37
37
  }
38
38
  get height() {
39
- this.checkDisposed("Media.height");
39
+ this.checkDisposed("Image.height");
40
40
  return this.payload.height;
41
41
  }
42
42
  get extension() {
43
- this.checkDisposed("Media.extension");
43
+ this.checkDisposed("Image.extension");
44
44
  return this.payload.extension;
45
45
  }
46
- get mediaType() {
47
- this.checkDisposed("Media.mediaType");
46
+ get mimeType() {
47
+ this.checkDisposed("Image.mimeType");
48
48
  const extension = this.extension;
49
49
  if (extension === "jpg" || extension === "jpeg") {
50
50
  return "image/jpeg";
@@ -64,7 +64,7 @@ class Media extends Content_1.Content {
64
64
  return "image/" + extension;
65
65
  }
66
66
  scaleToFit(boxSize, cropping) {
67
- this.checkDisposed("Media.scaleToFit");
67
+ this.checkDisposed("Image.scaleToFit");
68
68
  const zoom = boxSize / cropping.width;
69
69
  const scaledWidth = Math.floor(this.width * zoom);
70
70
  const scaledHeight = Math.floor(this.height * zoom);
@@ -77,9 +77,9 @@ class Media extends Content_1.Content {
77
77
  "height": scaledHeight
78
78
  };
79
79
  }
80
- static makeDefaultCropping(media) {
81
- const width = media.width;
82
- const height = media.height;
80
+ static makeDefaultCropping(image) {
81
+ const width = image.width;
82
+ const height = image.height;
83
83
  const isLandscapeOrSquare = width >= height;
84
84
  const isPortraitOrSquare = height >= width;
85
85
  const croppingOffsetTop = isLandscapeOrSquare ? 0 : Math.floor((height - width) / 2);
@@ -94,4 +94,4 @@ class Media extends Content_1.Content {
94
94
  };
95
95
  }
96
96
  }
97
- exports.Media = Media;
97
+ exports.Image = Image;
@@ -22,7 +22,7 @@ export interface ManifestEntry {
22
22
  export interface ManifestPayload {
23
23
  billing: any;
24
24
  device: any;
25
- media: any;
25
+ image: any;
26
26
  metric: any;
27
27
  profile: any;
28
28
  progress: any;
@@ -28,7 +28,7 @@ class Manifest extends Model_1.Model {
28
28
  payload: {
29
29
  billing: {},
30
30
  device: {},
31
- media: {},
31
+ image: {},
32
32
  metric: {},
33
33
  profile: {},
34
34
  progress: {},
@@ -1,12 +1,12 @@
1
1
  import { Doc } from '@shaxpir/sharedb/lib/client';
2
2
  import { ShareSync } from '../repo';
3
3
  import { Content, ContentBody, ContentId, ContentMeta } from "./Content";
4
- import { MediaCropping } from './Media';
4
+ import { ImageCropping } from './Image';
5
5
  export interface ProfilePayload {
6
6
  username: string;
7
7
  full_name: string;
8
- avatar_media_ref: ContentId;
9
- avatar_cropping: MediaCropping;
8
+ avatar_image_ref: ContentId;
9
+ avatar_cropping: ImageCropping;
10
10
  }
11
11
  export interface ProfileBody extends ContentBody {
12
12
  meta: ContentMeta;
@@ -21,9 +21,9 @@ export declare class Profile extends Content {
21
21
  setUsername(value: string): void;
22
22
  get fullName(): string;
23
23
  setFullName(value: string): void;
24
- get avatarMediaRef(): ContentId;
25
- setAvatarMediaRef(value: ContentId): void;
26
- get avatarCropping(): MediaCropping;
27
- setAvatarCropping(value: MediaCropping): void;
24
+ get avatarImageRef(): ContentId;
25
+ setAvatarImageRef(value: ContentId): void;
26
+ get avatarCropping(): ImageCropping;
27
+ setAvatarCropping(value: ImageCropping): void;
28
28
  static findByUsername(username: string): Promise<Profile[]>;
29
29
  }
@@ -25,7 +25,7 @@ class Profile extends Content_1.Content {
25
25
  payload: {
26
26
  username: null,
27
27
  full_name: '',
28
- avatar_media_ref: null,
28
+ avatar_image_ref: null,
29
29
  avatar_cropping: null
30
30
  }
31
31
  });
@@ -61,15 +61,15 @@ class Profile extends Content_1.Content {
61
61
  batch.commit();
62
62
  }
63
63
  }
64
- get avatarMediaRef() {
65
- this.checkDisposed("Profile.avatarMediaRef");
66
- return this.payload.avatar_media_ref;
64
+ get avatarImageRef() {
65
+ this.checkDisposed("Profile.avatarImageRef");
66
+ return this.payload.avatar_image_ref;
67
67
  }
68
- setAvatarMediaRef(value) {
69
- this.checkDisposed("Profile.setAvatarMediaRef");
70
- if (this.avatarMediaRef !== value) {
68
+ setAvatarImageRef(value) {
69
+ this.checkDisposed("Profile.setAvatarImageRef");
70
+ if (this.avatarImageRef !== value) {
71
71
  const batch = new Operation_1.BatchOperation(this);
72
- batch.setPathValue(['payload', 'avatar_media_ref'], value);
72
+ batch.setPathValue(['payload', 'avatar_image_ref'], value);
73
73
  batch.commit();
74
74
  }
75
75
  }
@@ -10,7 +10,7 @@ export * from './Flag';
10
10
  export * from './GeoLocation';
11
11
  export * from './Hanzi';
12
12
  export * from './Manifest';
13
- export * from './Media';
13
+ export * from './Image';
14
14
  export * from './Metric';
15
15
  export * from './Model';
16
16
  export * from './Operation';
@@ -27,7 +27,7 @@ __exportStar(require("./Flag"), exports);
27
27
  __exportStar(require("./GeoLocation"), exports);
28
28
  __exportStar(require("./Hanzi"), exports);
29
29
  __exportStar(require("./Manifest"), exports);
30
- __exportStar(require("./Media"), exports);
30
+ __exportStar(require("./Image"), exports);
31
31
  __exportStar(require("./Metric"), exports);
32
32
  __exportStar(require("./Model"), exports);
33
33
  __exportStar(require("./Operation"), exports);
@@ -419,8 +419,8 @@ class ShareSync {
419
419
  else if (kind === ContentKind_1.ContentKind.METRIC) {
420
420
  return new models_1.Metric(doc, shouldAcquire, shareSync);
421
421
  }
422
- else if (kind === ContentKind_1.ContentKind.MEDIA) {
423
- return new models_1.Media(doc, shouldAcquire, shareSync);
422
+ else if (kind === ContentKind_1.ContentKind.IMAGE) {
423
+ return new models_1.Image(doc, shouldAcquire, shareSync);
424
424
  }
425
425
  else if (kind === ContentKind_1.ContentKind.PROFILE) {
426
426
  return new models_1.Profile(doc, shouldAcquire, shareSync);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shaxpir/duiduidui-models",
3
- "version": "1.5.14",
3
+ "version": "1.6.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/shaxpir/duiduidui-models"
@@ -1,31 +0,0 @@
1
- import { Doc } from '@shaxpir/sharedb/lib/client';
2
- import { ShareSync } from '../repo';
3
- import { Content, ContentBody, ContentId, ContentMeta } from "./Content";
4
- export interface MediaDimensions {
5
- width: number;
6
- height: number;
7
- }
8
- export interface MediaCropping extends MediaDimensions {
9
- offset_top: number;
10
- offset_left: number;
11
- }
12
- export interface MediaPayload extends MediaDimensions {
13
- extension: string;
14
- bytes: number;
15
- }
16
- export interface MediaBody extends ContentBody {
17
- meta: ContentMeta;
18
- payload: MediaPayload;
19
- }
20
- export declare class Media extends Content {
21
- constructor(doc: Doc, shouldAcquire: boolean, shareSync: ShareSync);
22
- get payload(): MediaPayload;
23
- static create(userId: ContentId, mediaId: ContentId, payload: MediaPayload): Media;
24
- get bytes(): number;
25
- get width(): number;
26
- get height(): number;
27
- get extension(): string;
28
- get mediaType(): string;
29
- scaleToFit(boxSize: number, cropping: MediaCropping): MediaCropping;
30
- static makeDefaultCropping(media: Media): MediaCropping;
31
- }