diff --git a/bin/localization/data.csv b/bin/localization/data.csv index ae4835b6..01f81da4 100644 --- a/bin/localization/data.csv +++ b/bin/localization/data.csv @@ -370,6 +370,7 @@ list_tile.licenses.title,Licenses,التراخيص,Lizenzen,Licencias,Licencias, list_tile.moved_to_bin_at.title,Moved to bin,تم النقل إلى سلة المهملات,In den Papierkorb verschoben,Movido a la papelera,Movido a la papelera,Déplacé vers la corbeille,बिन में ले जाया गया,Dipindahkan ke tempat sampah,Spostato nel cestino,ゴミ箱に移動しました,ផ្លាស់ទីទៅធុងសំរាម,휴지통으로 옮겨졌어요,Przeniesiono do kosza,Movido para a lixeira,Đã chuyển vào thùng rác,已移至垃圾箱,Перемещено в корзину,Переміщено до кошика,Çöp kutusuna taşındı.,ย้ายไปถังขยะ list_tile.period_calendar.subtitle,Track your cycle and feelings,تتبع دورتك ومشاعرك,Verfolgen Sie Ihren Zyklus und Ihre Gefühle,Sigue tu ciclo y tus sentimientos,Sigue tu ciclo y tus sentimientos,Suivez votre cycle et vos sentiments,अपने चक्र और भावनाओं पर नज़र रखें,Lacak siklus dan perasaan Anda,Tieni traccia del tuo ciclo e delle tue sensazioni,周期と感情を追跡する,តាមដានវដ្តនិងអារម្មណ៍របស់អ្នក។,주기와 감정을 추적하세요,Śledź swój cykl i uczucia,Acompanhe seu ciclo e seus sentimentos,Theo dõi chu kỳ và cảm xúc của bạn,追踪你的周期和感受,Следите за циклом и своими чувствами.,Відстежуйте свій цикл і самопочуття,Adet döngünüzü ve hislerinizi takip edin.,ติดตามรอบเดือนและความรู้สึกของคุณ list_tile.period_calendar.title,Period Calendar,تقويم الدورة الشهرية,Menstruationskalender,Calendario menstrual,Calendario menstrual,Calendrier menstruel,मासिक धर्म कैलेंडर,Kalender Menstruasi,Calendario mestruale,月経カレンダー,ប្រតិទិនរដូវ,월경 달력,Kalendarz menstruacyjny,Calendário menstrual,Lịch kinh nguyệt,经期日历,Календарь менструаций,Календар менструальних періодів,Adet Takvimi,ปฏิทินช่วงเวลา +list_tile.photo_collage.title,Photo Collage,صورة مجمعة,Fotocollage,Collage de fotos,Collage de fotos,Collage photo,फोटो कोलाज़,Kolase Foto,Collage fotografico,フォトコラージュ,រូបថត​ចម្រុះ,사진 콜라주,Kolaż zdjęć,Colagem de fotos,Ảnh ghép,照片拼贴画,Фотоколлаж,Фотоколаж,Fotoğraf Kolajı,ภาพตัดต่อ list_tile.preview_char_count.title,Preview Character Count,عدد الأحرف في المعاينة,Vorschau Zeichenanzahl,Vista previa del recuento de caracteres,Vista previa del recuento de caracteres,Nombre de caractères d'aperçu,वर्णों की संख्या का पूर्वावलोकन,Pratinjau Jumlah Karakter,Anteprima del conteggio dei caratteri,プレビュー文字数,មើលជាមុនចំនួនតួអក្សរ,미리보기 문자 수,Podgląd liczby znaków,Contagem de caracteres de pré-visualização,Số ký tự xem trước,预览字符数,Предварительный просмотр количества символов,Попередній перегляд кількості символів,Karakter Sayısı Önizlemesi,จำนวนอักขระที่แสดงตัวอย่าง list_tile.product_hunt.title,Upvote us on {ARG_NAME},صوّت لنا على {ARG_NAME},Gib uns ein Upvote auf {ARG_NAME},Vota a favor de nosotros en {ARG_NAME},Vota a favor de nosotros en {ARG_NAME},Votez pour nous sur {ARG_NAME},{ARG_NAME} पर हमें अपवोट करें,Beri kami upvote di {ARG_NAME},Votaci su {ARG_NAME},{ARG_NAME}で私たちに賛成票をお願いします,បោះឆ្នោតគាំទ្រយើងលើ {ARG_NAME},{ARG_NAME}에서 저희를 추천해 주세요,Zagłosuj na nas na {ARG_NAME},Vote a favor de nós em {ARG_NAME},Hãy bình chọn cho chúng tôi trên {ARG_NAME},请在 {ARG_NAME} 上为我们点赞,Проголосуйте за нас на {ARG_NAME},Проголосуйте за нас на {ARG_NAME},Bizi {ARG_NAME} üzerinden oylayın.,กดโหวตสนับสนุนเราบน {ARG_NAME} list_tile.rate_on_store.title,Rate us on {ARG_NAME},قيّمونا على {ARG_NAME},Bewerten Sie uns auf {ARG_NAME},Califícanos en {ARG_NAME},Califícanos en {ARG_NAME},Évaluez-nous sur {ARG_NAME},हमें {ARG_NAME} पर रेट करें,Beri kami peringkat di {ARG_NAME},Valutaci su {ARG_NAME},{ARG_NAME}で評価してください。,វាយតម្លៃយើងនៅលើ {ARG_NAME},{ARG_NAME}에서 저희를 평가해 주세요.,Oceń nas na {ARG_NAME},Avalie-nos em {ARG_NAME},Đánh giá chúng tôi trên {ARG_NAME},请在 {ARG_NAME} 上给我们评分,Оцените нас на {ARG_NAME},Оцініть нас на {ARG_NAME},Bizi {ARG_NAME} üzerinden değerlendirin.,ให้คะแนนเราบน {ARG_NAME} @@ -445,14 +446,14 @@ page.home.app_bar.messages.we_syncing_ur_data,We're syncing your data,نحن ن page.home.app_bar.messages.what_in_ur_mind,What's on your mind?,ما الذي يدور في ذهنك؟,Was geht dir durch den Kopf?,¿Qué tienes en mente?,¿Qué tienes en mente?,Qu'est-ce qui préoccupe votre esprit?,आपके दिमाग में क्या है?,Apa yang ada di pikiranmu?,Cos'hai in mente?,今、何を考えていますか?,តើ​​អ្នកមាន​អ្វីនៅ​ក្នុង​ចិត្ត​?,지금 무슨 생각 중이세요?,Co masz na myśli?,O que está em sua mente?,Bạn đang nghĩ gì thế?,你正在想什么?,Поделишься своими мыслями?,Що у вас на думці?,Aklınızdan ne geçiyor?,คุณกำลังคิดอะไรอยู่? page.home.empty_message,Please click on {EDIT_BUTTON} to add story to {YEAR}.,برجاء النقر على {EDIT_BUTTON} لإضافة قصة إلى {YEAR}.,"Bitte klicken Sie auf {EDIT_BUTTON}, um die Geschichte zu {YEAR} hinzuzufügen.",Haga clic en {EDIT_BUTTON} para agregar una historia a {YEAR}.,Haga clic en {EDIT_BUTTON} para agregar una historia a {YEAR}.,Veuillez cliquer sur {EDIT_BUTTON} pour ajouter une histoire à {YEAR}.,कृपया {YEAR} में कहानी जोड़ने के लिए {EDIT_BUTTON} पर क्लिक करें।,Silakan klik {EDIT_BUTTON} untuk menambahkan cerita ke {YEAR}.,Fai clic su {EDIT_BUTTON} per aggiungere una storia a {YEAR}.,{EDIT_BUTTON} を押して、{YEAR} にストーリーを追加しましょう。,សូមចុចលើ {EDIT_BUTTON} ដើម្បីបន្ថែមរឿងទៅ {YEAR}។,{YEAR}에 스토리를 추가하려면 {EDIT_BUTTON}을 눌러주세요,"Kliknij {EDIT_BUTTON}, aby dodać historię do roku {YEAR}.",Clique em {EDIT_BUTTON} para adicionar uma história a {YEAR}.,Vui lòng nhấp vào {EDIT_BUTTON} để thêm câu chuyện vào {YEAR}.,请点击 {EDIT_BUTTON} 将故事添加到 {YEAR}。,Пожалуйста тапните на {EDIT_BUTTON} чтобы добавить историю на {YEAR}.,"Будь ласка, натисніть на {EDIT_BUTTON}, щоб додати розповідь до {YEAR}.",Lütfen {EDIT_BUTTON}ne tıklayarak {YEAR} yılına hikaye ekleyin.,โปรดคลิกที่ปุ่มแก้ไข (EDIT_BUTTON) เพื่อเพิ่มเรื่องราวลงในปี {YEAR} page.home.story_recap.active_days,{SP_ACTIVE} of {SP_TOTAL} days,{SP_ACTIVE} من {SP_TOTAL} يومًا,{SP_ACTIVE} von {SP_TOTAL} Tagen,{SP_ACTIVE} de {SP_TOTAL} días,{SP_ACTIVE} de {SP_TOTAL} días,{SP_ACTIVE} de {SP_TOTAL} jours,{SP_ACTIVE} दिनों में से {SP_TOTAL} दिन,{SP_ACTIVE} dari {SP_TOTAL} hari,{SP_ACTIVE} di {SP_TOTAL} giorni,{SP_ACTIVE}日間のうち{SP_TOTAL}日間,{SP_ACTIVE} នៃ {SP_TOTAL} ថ្ងៃ,{SP_ACTIVE}일 (총 {SP_TOTAL}일),{SP_ACTIVE} z {SP_TOTAL} dni,{SP_ACTIVE} de {SP_TOTAL} dias,{SP_ACTIVE} trong tổng số {SP_TOTAL} ngày,{SP_ACTIVE} 共 {SP_TOTAL} 天,{SP_ACTIVE} из {SP_TOTAL} дней,{SP_ACTIVE} з {SP_TOTAL} днів,{SP_ACTIVE} / {SP_TOTAL} gün,{SP_ACTIVE} ของ {SP_TOTAL} วัน -page.home.story_recap.title,{SP_MONTH} Highlights,ملخص شهر {SP_MONTH},Zusammenfassung des Monats {SP_MONTH},Resumen del mes de {SP_MONTH},Resumen del mes de {SP_MONTH},Récapitulatif de {SP_MONTH},{SP_MONTH} का सारांश,Rekap Bulan {SP_MONTH},Riepilogo di {SP_MONTH},{SP_MONTH}のまとめ,សេចក្តីសង្ខេបនៃខែ {SP_MONTH},{SP_MONTH}의 요약,Podsumowanie {SP_MONTH},Resumo do mês de SP,Tóm tắt tháng {SP_MONTH},{SP_MONTH} 的回顾,Итоги {SP_MONTH},Огляд за {SP_MONTH},{SP_MONTH}'un Özeti,สรุปกิจกรรมของ {SP_MONTH} +page.home.story_recap.title,{SP_MONTH} Highlights,ملخص شهر {SP_MONTH},Zusammenfassung des Monats {SP_MONTH},Resumen del mes de {SP_MONTH},Resumen del mes de {SP_MONTH},Récapitulatif de {SP_MONTH},{SP_MONTH} का सारांश,Rekap Bulan {SP_MONTH},Riepilogo di {SP_MONTH},{SP_MONTH}のまとめ,សេចក្តីសង្ខេបនៃខែ {SP_MONTH},{SP_MONTH}의 요약,Podsumowanie {SP_MONTH},Destaques de {SP_MONTH},Tóm tắt tháng {SP_MONTH},{SP_MONTH} 的回顾,Итоги {SP_MONTH},Огляд за {SP_MONTH},{SP_MONTH}'un Özeti,สรุปกิจกรรมของ {SP_MONTH} page.home.title,Home,بيت,Zuhause,Hogar,Hogar,Maison,घर,Rumah,Casa,家,ផ្ទះ,집,Dom,Lar,Trang chủ,家,Хайм,Головна,Ev,บ้าน page.image_picker.empty_message,Added photos will appear here.,ستظهر الصور المضافة هنا.,Hinzugefügte Fotos werden hier angezeigt.,Las fotos agregadas aparecerán aquí.,Las fotos agregadas aparecerán aquí.,Les photos ajoutées apparaîtront ici.,जोड़ी गई तस्वीरें यहां दिखाई देंगी.,Foto yang ditambahkan akan muncul di sini.,Le foto aggiunte appariranno qui.,追加した写真はここに表示されます。,រូបថតដែលបានបន្ថែមនឹងបង្ហាញនៅទីនេះ។,추가된 사진이 여기에 표시됩니다.,Dodane zdjęcia pojawią się tutaj.,As fotos adicionadas aparecerão aqui.,Ảnh đã thêm sẽ xuất hiện ở đây.,添加的照片将显示在这里。,Добавленные изображения хранятся здесь.,Додані фотографії з'являться тут.,Eklenen fotoğraflar burada görünecektir.,รูปภาพที่เพิ่มเข้ามาจะปรากฏที่นี่ page.import_export_backup,Import / Export,استيراد / تصدير البيانات,Daten importieren/exportieren,Importar/Exportar datos,Importar/Exportar datos,Données d'importation/exportation,डेटा आयात/निर्यात करें,Impor / Ekspor Data,Importa/Esporta dati,データのインポート/エクスポート,នាំចូល/នាំចេញទិន្នន័យ,데이터 가져오기/내보내기,Import/Eksport danych,Dados de importação/exportação,Nhập / Xuất dữ liệu,导入/导出数据,Daten importieren/exportieren,Імпорт / Експорт,İçe Aktar / Dışa Aktar,นำเข้า/ส่งออก page.language.title,Language,لغة,Sprache,Idioma,Idioma,Langue,भाषा,Bahasa,Lingua,言語,ភាសា,언어,Język,Linguagem,Ngôn ngữ,语言,Язык,Мова,Dil,ภาษา page.library.empty_message,Items will appear here.,ستظهر العناصر هنا.,Die Artikel werden hier angezeigt.,Los artículos aparecerán aquí.,Los artículos aparecerán aquí.,Les articles apparaîtront ici.,आइटम यहां दिखाई देंगे.,Item akan muncul di sini.,Gli articoli appariranno qui.,ここにアイテムが表示されます。,ធាតុនឹងបង្ហាញនៅទីនេះ។,항목이 여기에 표시됩니다.,Tutaj pojawią się elementy.,Os itens aparecerão aqui.,Các mục sẽ xuất hiện ở đây.,物品将显示在此处。,Die Artikel werden hier angezeigt.,Тут з'являться елементи.,Ürünler burada görünecektir.,รายการต่างๆ จะปรากฏที่นี่ -page.library.title,Media,وسائط,Medien,Medios de comunicación,Medios de comunicación,Médias,मिडिया,Media,Media,メディア,មេឌៀ,메디아,Głoska bezdźwięczna,Mídia,Phương tiện truyền thông,媒体,СМИ,Медіа,Medya,สื่อ -page.library.title_with_app_name,StoryPad Media,ستوري باد ميديا,StoryPad Media,StoryPad Media,StoryPad Media,StoryPad Media,स्टोरीपैड मीडिया,StoryPad Media,StoryPad Media,ストーリーパッド・メディア,មេឌៀ StoryPad,스토리패드 미디어,StoryPad Media,StoryPad Media,StoryPad Media,StoryPad Media,StoryPad Media,StoryPad Media,StoryPad Medya,สตอรี่แพดมีเดีย +page.library.title,Media,وسائط,Medien,Medios de comunicación,Medios de comunicación,Médias,मिडिया,Media,Media,メディア,មេឌៀ,미디어,Media,Mídia,Phương tiện truyền thông,媒体,СМИ,Медіа,Medya,สื่อ +page.library.title_with_app_name,StoryPad Media,ستوري باد ميديا,StoryPad Media,StoryPad Media,StoryPad Media,StoryPad Media,स्टोरीपैड मीडिया,StoryPad Media,StoryPad Media,ストーリーパッド・メディア,មេឌៀ StoryPad,스토리패드 미디어,StoryPad Media,StoryPad Mídia,StoryPad Media,StoryPad 媒体,StoryPad Media,StoryPad Media,StoryPad Medya,สตอรี่แพดมีเดีย page.map.edit_place.recent_labels,Recent labels,التصنيفات الأخيرة,Letzte Labels,Etiquetas recientes,Etiquetas recientes,Étiquettes récentes,हाल के लेबल,Label terbaru,Etichette recenti,最近のラベル,ស្លាកថ្មីៗ,최근 라벨,Ostatnie etykiety,Rótulos recentes,Nhãn gần đây,近期标签,Недавние этикетки,Нещодавні мітки,Son etiketler,ป้ายกำกับล่าสุด page.map.edit_place.title,Edit place name,تعديل اسم المكان,Ortsnamen bearbeiten,Editar nombre del lugar,Editar nombre del lugar,Modifier le nom du lieu,स्थान का नाम संपादित करें,Edit nama tempat,Modifica il nome del luogo,場所の名前を編集する,កែសម្រួលឈ្មោះទីកន្លែង,장소 이름 수정,Edytuj nazwę miejsca,Editar nome do local,Chỉnh sửa tên địa điểm,编辑地名,Изменить название места,Редагувати назву місця,Yer adını düzenle,แก้ไขชื่อสถานที่ page.map.picker.messages.drag_map_to_select_place,Drag map to select a place,اسحب الخريطة لتحديد مكان,"Ziehen Sie die Karte, um einen Ort auszuwählen.",Arrastra el mapa para seleccionar un lugar.,Arrastra el mapa para seleccionar un lugar.,Faites glisser la carte pour sélectionner un lieu,किसी स्थान का चयन करने के लिए मानचित्र को खींचें,Seret peta untuk memilih tempat.,Trascina la mappa per selezionare un luogo,地図をドラッグして場所を選択してください,អូសផែនទីដើម្បីជ្រើសរើសកន្លែងមួយ,지도를 드래그하여 장소를 선택하세요,"Przeciągnij mapę, aby wybrać miejsce",Arraste o mapa para selecionar um local.,Kéo bản đồ để chọn một địa điểm,拖动地图选择位置,"Перетащите карту, чтобы выбрать место.","Перетягніть карту, щоб вибрати місце",Haritayı sürükleyerek bir yer seçin.,ลากแผนที่เพื่อเลือกสถานที่ @@ -528,11 +529,11 @@ paywall_features.templates.title,Templates,القوالب,Vorlagen,Plantillas,Pl plural.day_ago.one,1 day ago,منذ يوم واحد,Vor 1 Tag,Hace 1 día,Hace 1 día,il y a 1 jour,1 दिन पहले,1 hari yang lalu,1 giorno fa,1日前,1 ថ្ងៃមុន,1일 전,1 dzień temu,1 dia atrás,1 ngày trước,1 天前,1 день назад,1 день тому,1 gün önce,1 วันที่แล้ว plural.day_ago.other,{} days ago,{} منذ أيام,Vor {} Tagen,{} días atrás,{} días atrás,il y a {} jours,{} दिन पहले,{} hari yang lalu,{} giorni fa,{} 日前,{} ថ្ងៃមុន,{}일 전,{} dni temu,{} dias atrás,{} ngày trước,{} 天前,{} дней назад,{} днів тому,{} gün önce,{} วันที่ผ่านมา plural.entry.one,1 entry,مدخل واحد,1 Eintrag,1 entrada,1 entrada,1 entrée,1 प्रविष्टि,1 entri,1 voce,1件のエントリー,ធាតុចូលចំនួន ១,1개 항목,1 wpis,1 entrada,1 mục,1 条记录,1 запись,1 запис,1 giriş,1 รายการ -plural.entry.other,{} entries,{} إدخالات,{} Einträge,{} entradas,{} entradas,{} entrées,{} प्रविष्टियाँ,entri {},{} voci,{} エントリ,ធាតុ {},{} 항목,{} wpisów,entradas {},{} mục,{} 条目,{} записей,{} записів,{} girişler,{} รายการ +plural.entry.other,{} entries,{} إدخالات,{} Einträge,{} entradas,{} entradas,{} entrées,{} प्रविष्टियाँ,entri {},{} voci,{} エントリ,ធាតុ {},{} 항목,{} wpisów,{} entradas,{} mục,{} 条目,{} записей,{} записів,{} giriş,{} รายการ plural.page.one,1 page,1 صفحة,1 Seite,1 página,1 página,1 page,1 पेज,1 halaman,1 pagina,1ページ,1 ទំព័រ,1페이지,1 strona,1 página,1 trang,1 页,1 страница,1 сторінка,1 sayfa,1 หน้า plural.page.other,{} pages,{} صفحات,{} Seiten,{} páginas,{} páginas,{} pages,{} पेज,{} halaman,{} pagine,{} ページ,{} ទំព័រ,{} 페이지,{} stron,{} páginas,{} trang,{} 页,{} страниц,{} сторінок,{} sayfa,{} หน้า plural.photo.one,1 photo,صورة واحدة,1 Foto,1 foto,1 foto,1 photo,1 फोटो,1 foto,1 foto,写真1枚,រូបថត ១ សន្លឹក,사진 1장,1 zdjęcie,1 foto,1 ảnh,1张照片,1 фото,1 фото,1 fotoğraf,1 รูป -plural.photo.other,{} photos,{} صور,{} Fotos,{} fotos,{} fotos,{} photos,{} फ़ोटो,foto {},{} foto,{} 写真,រូបថត {},{} 사진,{} zdjęć,{} fotos,{} ảnh,{} 照片,{} фотографии,{} фотографій,{} fotoğraflar,{} รูปภาพ +plural.photo.other,{} photos,{} صور,{} Fotos,{} fotos,{} fotos,{} photos,{} फ़ोटो,foto {},{} foto,{} 写真,រូបថត {},{} 사진,{} zdjęć,{} fotos,{} ảnh,{} 照片,{} фотографии,{} фотографій,{} fotoğraf,{} รูปภาพ plural.row.one,1 row,1 صف,1 Reihe,1 fila,1 fila,1 rangée,1 पंक्ति,1 baris,1 riga,1行,1 ជួរ,1줄,1 rząd,1 linha,1 hàng,1 行,1 элемент,1 ряд,1 satır,แถวที่ 1 plural.row.other,{} rows,{} صفوف,{} Zeilen,{} filas,{} filas,{} lignes,{}पंक्तियाँ,{} baris,{} righe,{} 行,{} ជួរ,{}줄,{} wierszy,{} linhas,{} hàng,{} 行,{} элементов,{} рядків,{} satır,{} แถว plural.voice.one,1 voice,صوت واحد,1 Stimme,1 voz,1 voz,1 voix,1 आवाज़,1 suara,1 voce,1人の声,1 សំឡេង,1 음성,1 głos,1 voz,1 giọng nói,1 人声,1 Стимме,1 голосове,1 ses,1 เสียง diff --git a/lib/core/objects/story_tile_preferences_object.dart b/lib/core/objects/story_tile_preferences_object.dart index 46426257..351d5e00 100644 --- a/lib/core/objects/story_tile_preferences_object.dart +++ b/lib/core/objects/story_tile_preferences_object.dart @@ -12,6 +12,7 @@ class StoryTilePreferencesObject { final bool showPeopleLabels; final bool showVoiceCount; final bool showLocation; + final bool photoCollage; final int displayCharacterCount; StoryTilePreferencesObject({ @@ -21,6 +22,7 @@ class StoryTilePreferencesObject { bool? showPeopleLabels, bool? showVoiceCount, bool? showLocation, + bool? photoCollage, int? displayCharacterCount, }) : showTime = showTime ?? true, showPageCount = showPageCount ?? true, @@ -28,6 +30,7 @@ class StoryTilePreferencesObject { showPeopleLabels = showPeopleLabels ?? true, showVoiceCount = showVoiceCount ?? true, showLocation = showLocation ?? true, + photoCollage = photoCollage ?? false, displayCharacterCount = displayCharacterCount ?? 200; // During user editing, we can show all content without limit. diff --git a/lib/core/objects/story_tile_preferences_object.g.dart b/lib/core/objects/story_tile_preferences_object.g.dart index 1bbb19d7..8166936b 100644 --- a/lib/core/objects/story_tile_preferences_object.g.dart +++ b/lib/core/objects/story_tile_preferences_object.g.dart @@ -19,6 +19,8 @@ abstract class _$StoryTilePreferencesObjectCWProxy { StoryTilePreferencesObject showLocation(bool? showLocation); + StoryTilePreferencesObject photoCollage(bool? photoCollage); + StoryTilePreferencesObject displayCharacterCount(int? displayCharacterCount); /// Creates a new instance with the provided field values. @@ -35,6 +37,7 @@ abstract class _$StoryTilePreferencesObjectCWProxy { bool? showPeopleLabels, bool? showVoiceCount, bool? showLocation, + bool? photoCollage, int? displayCharacterCount, }); } @@ -71,6 +74,10 @@ class _$StoryTilePreferencesObjectCWProxyImpl StoryTilePreferencesObject showLocation(bool? showLocation) => call(showLocation: showLocation); + @override + StoryTilePreferencesObject photoCollage(bool? photoCollage) => + call(photoCollage: photoCollage); + @override StoryTilePreferencesObject displayCharacterCount( int? displayCharacterCount, @@ -91,6 +98,7 @@ class _$StoryTilePreferencesObjectCWProxyImpl Object? showPeopleLabels = const $CopyWithPlaceholder(), Object? showVoiceCount = const $CopyWithPlaceholder(), Object? showLocation = const $CopyWithPlaceholder(), + Object? photoCollage = const $CopyWithPlaceholder(), Object? displayCharacterCount = const $CopyWithPlaceholder(), }) { return StoryTilePreferencesObject( @@ -118,6 +126,10 @@ class _$StoryTilePreferencesObjectCWProxyImpl ? _value.showLocation // ignore: cast_nullable_to_non_nullable : showLocation as bool?, + photoCollage: photoCollage == const $CopyWithPlaceholder() + ? _value.photoCollage + // ignore: cast_nullable_to_non_nullable + : photoCollage as bool?, displayCharacterCount: displayCharacterCount == const $CopyWithPlaceholder() ? _value.displayCharacterCount @@ -148,6 +160,7 @@ StoryTilePreferencesObject _$StoryTilePreferencesObjectFromJson( showPeopleLabels: json['show_people_labels'] as bool?, showVoiceCount: json['show_voice_count'] as bool?, showLocation: json['show_location'] as bool?, + photoCollage: json['photo_collage'] as bool?, displayCharacterCount: (json['display_character_count'] as num?)?.toInt(), ); @@ -160,5 +173,6 @@ Map _$StoryTilePreferencesObjectToJson( 'show_people_labels': instance.showPeopleLabels, 'show_voice_count': instance.showVoiceCount, 'show_location': instance.showLocation, + 'photo_collage': instance.photoCollage, 'display_character_count': instance.displayCharacterCount, }; diff --git a/lib/views/day_colors/day_colors_view.dart b/lib/views/day_colors/day_colors_view.dart index 557519cb..bd6a6994 100644 --- a/lib/views/day_colors/day_colors_view.dart +++ b/lib/views/day_colors/day_colors_view.dart @@ -9,8 +9,8 @@ import 'package:storypad/providers/device_preferences_provider.dart'; import 'package:storypad/providers/in_app_purchase_provider.dart'; import 'package:storypad/views/paywall/paywall_view.dart'; import 'package:storypad/widgets/base_view/base_route.dart'; +import 'package:storypad/widgets/sp_adaptive_pop_up_button.dart'; import 'package:storypad/widgets/sp_color_picker.dart'; -import 'package:storypad/widgets/sp_floating_pop_up_button.dart'; import 'package:storypad/widgets/sp_icons.dart'; import 'package:storypad/widgets/sp_pop_up_menu_button.dart'; import 'package:storypad/widgets/sp_theme_mode_icon.dart'; diff --git a/lib/views/settings/local_widgets/default_story_preferences_tile.dart b/lib/views/settings/local_widgets/default_story_preferences_tile.dart index bc7554f3..22cb0249 100644 --- a/lib/views/settings/local_widgets/default_story_preferences_tile.dart +++ b/lib/views/settings/local_widgets/default_story_preferences_tile.dart @@ -22,9 +22,17 @@ class DefaultStoryPreferencesTile extends StatelessWidget { title: Text(tr("list_tile.default_story_preferences.title")), trailing: locked ? const Icon(SpIcons.lock) : null, onTap: () async { - final result = await const SpDefaultStoryPreferencesSheet().show(context: context); - if (context.mounted && result is DefaultStoryPreferencesObject) { - context.read().setDefaultStoryPreferences(result); + // The sheet has no save button for pro users; it reports its live draft and + // we commit it once here, after the sheet closes. + DefaultStoryPreferencesObject? draft; + await SpDefaultStoryPreferencesSheet(onChanged: (result) => draft = result).show(context: context); + + if (!context.mounted || draft == null) return; + + // Non-pro users are gated by the locked save button inside the sheet (paywall), + // so their draft is never persisted here. + if (context.read().isProUser) { + context.read().setDefaultStoryPreferences(draft!); } }, ); diff --git a/lib/views/settings/local_widgets/story_tile_preferences_tile.dart b/lib/views/settings/local_widgets/story_tile_preferences_tile.dart index 5e395b82..0bf6d242 100644 --- a/lib/views/settings/local_widgets/story_tile_preferences_tile.dart +++ b/lib/views/settings/local_widgets/story_tile_preferences_tile.dart @@ -22,14 +22,21 @@ class StoryTilePreferencesTile extends StatelessWidget { title: Text(tr("list_tile.story_tile_preferences.title")), trailing: locked ? const Icon(SpIcons.lock) : null, onTap: () async { - final result = await const SpStoryTilePreferencesSheet().show(context: context); + // The sheet has no save button for pro users; it reports its live draft and + // we commit it once here, after the sheet closes. + StoryTilePreferencesObject? draft; + await SpStoryTilePreferencesSheet(onChanged: (result) => draft = result).show(context: context); // delay to ensure the bottom sheet is fully closed before applying the new preferences, // which can trigger a rebuild of the story list and cause jank if done too early. await Future.delayed(const Duration(milliseconds: 500)); - if (context.mounted && result is StoryTilePreferencesObject) { - context.read().setStoryTilePreferences(result); + if (!context.mounted || draft == null) return; + + // Non-pro users are gated by the locked save button inside the sheet (paywall), + // so their draft is never persisted here. + if (context.read().isProUser) { + context.read().setStoryTilePreferences(draft!); } }, ); diff --git a/lib/widgets/bottom_sheets/sp_default_story_preferences_sheet.dart b/lib/widgets/bottom_sheets/sp_default_story_preferences_sheet.dart index abeaa2af..8b662f61 100644 --- a/lib/widgets/bottom_sheets/sp_default_story_preferences_sheet.dart +++ b/lib/widgets/bottom_sheets/sp_default_story_preferences_sheet.dart @@ -15,7 +15,11 @@ import 'package:storypad/widgets/sp_icons.dart'; import 'package:storypad/widgets/sp_layout_type_section.dart'; class SpDefaultStoryPreferencesSheet extends BaseBottomSheet { - const SpDefaultStoryPreferencesSheet(); + const SpDefaultStoryPreferencesSheet({this.onChanged}); + + /// Reports the live draft on every change ([null] when nothing differs from + /// the saved value). The caller commits it after the sheet closes. + final void Function(DefaultStoryPreferencesObject? preferences)? onChanged; @override bool get fullScreen => true; @@ -42,6 +46,7 @@ class SpDefaultStoryPreferencesSheet extends BaseBottomSheet { Widget buildView(BuildContext context, double bottomPadding) { return _StoryEditingPreferencesSheetContent( bottomPadding: bottomPadding, + onChanged: onChanged, ); } } @@ -49,9 +54,11 @@ class SpDefaultStoryPreferencesSheet extends BaseBottomSheet { class _StoryEditingPreferencesSheetContent extends StatefulWidget { const _StoryEditingPreferencesSheetContent({ required this.bottomPadding, + this.onChanged, }); final double bottomPadding; + final void Function(DefaultStoryPreferencesObject? preferences)? onChanged; @override State<_StoryEditingPreferencesSheetContent> createState() => _StoryEditingPreferencesSheetContentState(); @@ -68,6 +75,11 @@ class _StoryEditingPreferencesSheetContentState extends State<_StoryEditingPrefe bool get resettable => jsonEncode(defaultStoryPreferences.toJson()) != jsonEncode(defaultStoryPreferencesDefault.toJson()); + void _apply(DefaultStoryPreferencesObject next) { + setState(() => defaultStoryPreferences = next); + widget.onChanged?.call(changed ? defaultStoryPreferences : null); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -76,25 +88,28 @@ class _StoryEditingPreferencesSheetContentState extends State<_StoryEditingPrefe title: Text(tr("list_tile.default_story_preferences.title")), automaticallyImplyLeading: !CupertinoSheetRoute.hasParentSheet(context), actions: [ - if (changed) + // Pro users save automatically when the sheet closes, so no save button. + // Non-pro users keep a locked save button that opens the paywall; they can + // still preview changes but cannot persist them. + if (changed && !Provider.of(context).isProUser) IconButton( tooltip: tr("button.done"), - icon: Icon(SpIcons.save, color: Theme.of(context).colorScheme.primary), - onPressed: changed - ? () { - if (context.read().isProUser) { - Navigator.maybePop(context, defaultStoryPreferences); - } else { - const PaywallRoute(initialFocus: .customizations).push(context); - } - } - : null, + icon: Stack( + clipBehavior: Clip.none, + children: [ + Icon(SpIcons.save, color: Theme.of(context).colorScheme.primary), + const Positioned( + top: -2, + right: -8, + child: Icon(SpIcons.lock, size: 12.0), + ), + ], + ), + onPressed: () => const PaywallRoute(initialFocus: .customizations).push(context), ), IconButton( icon: const Icon(SpIcons.refresh), - onPressed: resettable - ? () => setState(() => defaultStoryPreferences = defaultStoryPreferencesDefault) - : null, + onPressed: resettable ? () => _apply(defaultStoryPreferencesDefault) : null, ), if (CupertinoSheetRoute.hasParentSheet(context)) CloseButton(onPressed: () => CupertinoSheetRoute.popSheet(context)), @@ -110,20 +125,20 @@ class _StoryEditingPreferencesSheetContentState extends State<_StoryEditingPrefe colorTone: defaultStoryPreferences.defaultColorTone, backgroundImagePath: defaultStoryPreferences.defaultBackgroundImagePath, onThemeChanged: ({colorSeedValue, colorTone, backgroundImagePath}) { - defaultStoryPreferences = defaultStoryPreferences.copyWith( - defaultColorSeedValue: colorSeedValue, - defaultColorTone: colorTone, - defaultBackgroundImagePath: backgroundImagePath, + _apply( + defaultStoryPreferences.copyWith( + defaultColorSeedValue: colorSeedValue, + defaultColorTone: colorTone, + defaultBackgroundImagePath: backgroundImagePath, + ), ); - setState(() {}); }, ), const SizedBox(height: 12.0), SpLayoutTypeSection( selected: defaultStoryPreferences.defaultLayoutType, onThemeChanged: (layoutType) { - defaultStoryPreferences = defaultStoryPreferences.copyWith(defaultLayoutType: layoutType); - setState(() {}); + _apply(defaultStoryPreferences.copyWith(defaultLayoutType: layoutType)); }, ), SizedBox(height: widget.bottomPadding), diff --git a/lib/widgets/bottom_sheets/sp_story_tile_preferences_sheet.dart b/lib/widgets/bottom_sheets/sp_story_tile_preferences_sheet.dart index b228f511..fdb1490e 100644 --- a/lib/widgets/bottom_sheets/sp_story_tile_preferences_sheet.dart +++ b/lib/widgets/bottom_sheets/sp_story_tile_preferences_sheet.dart @@ -6,6 +6,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:storypad/core/constants/app_constants.dart'; +import 'package:storypad/core/databases/models/asset_db_model.dart'; import 'package:storypad/core/databases/models/place_db_model.dart'; import 'package:storypad/core/databases/models/story_content_db_model.dart'; import 'package:storypad/core/databases/models/story_db_model.dart'; @@ -13,6 +14,7 @@ import 'package:storypad/core/databases/models/story_page_db_model.dart'; import 'package:storypad/core/databases/models/tag_category_db_model.dart'; import 'package:storypad/core/databases/models/tag_db_model.dart'; import 'package:storypad/core/objects/story_tile_preferences_object.dart'; +import 'package:storypad/core/types/asset_type.dart'; import 'package:storypad/providers/device_preferences_provider.dart'; import 'package:storypad/providers/in_app_purchase_provider.dart'; import 'package:storypad/providers/tags_provider.dart'; @@ -24,7 +26,12 @@ import 'package:storypad/widgets/sp_setting_icon_badge.dart'; import 'package:storypad/widgets/story_list/sp_story_tile.dart'; class SpStoryTilePreferencesSheet extends BaseBottomSheet { - const SpStoryTilePreferencesSheet(); + const SpStoryTilePreferencesSheet({this.onChanged}); + + /// Reports the live draft on every change ([null] when nothing differs from + /// the saved value). The caller commits it after the sheet closes, so the + /// global preferences only change once — avoiding story list jank mid-sheet. + final void Function(StoryTilePreferencesObject? preferences)? onChanged; @override bool get fullScreen => true; @@ -58,6 +65,7 @@ class SpStoryTilePreferencesSheet extends BaseBottomSheet { Widget buildView(BuildContext context, double bottomPadding) { return _StoryTilePreferencesSheetContent( bottomPadding: bottomPadding, + onChanged: onChanged, ); } } @@ -65,9 +73,11 @@ class SpStoryTilePreferencesSheet extends BaseBottomSheet { class _StoryTilePreferencesSheetContent extends StatefulWidget { const _StoryTilePreferencesSheetContent({ required this.bottomPadding, + this.onChanged, }); final double bottomPadding; + final void Function(StoryTilePreferencesObject? preferences)? onChanged; @override State<_StoryTilePreferencesSheetContent> createState() => _StoryTilePreferencesSheetContentState(); @@ -90,16 +100,44 @@ class _StoryTilePreferencesSheetContentState extends State<_StoryTilePreferences if (!TagDbModel.db.exist(_demoActivityTag.id)) await TagDbModel.db.set(_demoActivityTag); } - late final story = _buildMockStory(); + late StoryDbModel story = _buildMockStory(); late final simpleStory = _buildSimpleMockStory(); + final ScrollController _optionsScrollController = ScrollController(); + + // Real image paths sampled from the user's assets so the preview can demo the + // photo collage. Empty when the user has no images yet. + List _previewImagePaths = []; + bool get changed => jsonEncode(storyTilePreferences.toJson()) != jsonEncode(initialStoryTilePreferences.toJson()); bool get resettable => jsonEncode(storyTilePreferences.toJson()) != jsonEncode(defaultStoryTilePreferences.toJson()); + void _apply(StoryTilePreferencesObject next) { + setState(() => storyTilePreferences = next); + widget.onChanged?.call(changed ? storyTilePreferences : null); + } + @override void initState() { super.initState(); _ensureDemoFeelingTag(); + _loadPreviewImages(); + } + + @override + void dispose() { + _optionsScrollController.dispose(); + super.dispose(); + } + + Future _loadPreviewImages() async { + final collection = await AssetDbModel.db.where(filters: {'type': AssetType.image, 'limit': 3}); + final images = collection?.items.map((e) => e.relativeLocalFilePath).toList(); + if (images == null || images.isEmpty || !mounted) return; + setState(() { + _previewImagePaths = images; + story = _buildMockStory(); + }); } StoryDbModel _buildMockStory() { @@ -113,7 +151,13 @@ class _StoryTilePreferencesSheetContentState extends State<_StoryTilePreferences "with a warm cup of coffee before diving into work."; final delta = Delta() ..insert(body) - ..insert("\n") + ..insert("\n"); + if (_previewImagePaths.isNotEmpty) { + delta + ..insert({"image": _previewImagePaths.join('|')}) + ..insert("\n"); + } + delta ..insert({"audio": "audio/mock_voice_1.m4a"}) ..insert("\n") ..insert({"audio": "audio/mock_voice_2.m4a"}); @@ -193,23 +237,28 @@ class _StoryTilePreferencesSheetContentState extends State<_StoryTilePreferences title: Text(tr("list_tile.story_tile_preferences.title")), automaticallyImplyLeading: !CupertinoSheetRoute.hasParentSheet(context), actions: [ - if (changed) + // Pro users save automatically when the sheet closes, so no save button. + // Non-pro users keep a locked save button that opens the paywall; they can + // still preview changes but cannot persist them. + if (changed && !Provider.of(context).isProUser) IconButton( tooltip: tr("button.done"), - icon: Icon(SpIcons.save, color: Theme.of(context).colorScheme.primary), - onPressed: changed - ? () { - if (context.read().isProUser) { - Navigator.maybePop(context, storyTilePreferences); - } else { - const PaywallRoute(initialFocus: .customizations).push(context); - } - } - : null, + icon: Stack( + clipBehavior: Clip.none, + children: [ + Icon(SpIcons.save, color: Theme.of(context).colorScheme.primary), + const Positioned( + top: -2, + right: -8, + child: Icon(SpIcons.lock, size: 12.0), + ), + ], + ), + onPressed: () => const PaywallRoute(initialFocus: .customizations).push(context), ), IconButton( icon: const Icon(SpIcons.refresh), - onPressed: resettable ? () => setState(() => storyTilePreferences = defaultStoryTilePreferences) : null, + onPressed: resettable ? () => _apply(defaultStoryTilePreferences) : null, ), if (CupertinoSheetRoute.hasParentSheet(context)) CloseButton(onPressed: () => CupertinoSheetRoute.popSheet(context)), @@ -217,73 +266,81 @@ class _StoryTilePreferencesSheetContentState extends State<_StoryTilePreferences ), body: ListView( controller: PrimaryScrollController.maybeOf(context), + padding: const EdgeInsets.only(top: 8.0), children: [ - SwitchListTile.adaptive( - secondary: const SpSettingIconBadge(weekday: 1, icon: SpIcons.timer), - contentPadding: const EdgeInsets.only(left: 16.0, right: 12.0), - title: Text(tr("list_tile.show_time.title")), - value: storyTilePreferences.showTime, - onChanged: (value) { - storyTilePreferences = storyTilePreferences.copyWith(showTime: value); - setState(() {}); - }, - ), - SwitchListTile.adaptive( - secondary: const SpSettingIconBadge(weekday: 2, icon: SpIcons.voice), - contentPadding: const EdgeInsets.only(left: 16.0, right: 12.0), - title: Text(tr("list_tile.show_voice_count.title")), - value: storyTilePreferences.showVoiceCount, - onChanged: (value) { - storyTilePreferences = storyTilePreferences.copyWith(showVoiceCount: value); - setState(() {}); - }, - ), - SwitchListTile.adaptive( - secondary: const SpSettingIconBadge(weekday: 3, icon: SpIcons.tag), - contentPadding: const EdgeInsets.only(left: 16.0, right: 12.0), - title: Text(tr("list_tile.show_tag_labels.title")), - value: storyTilePreferences.showTagLabels, - onChanged: (value) { - storyTilePreferences = storyTilePreferences.copyWith(showTagLabels: value); - setState(() {}); - }, - ), - SwitchListTile.adaptive( - secondary: const SpSettingIconBadge(weekday: 7, icon: SpIcons.alternateEmail), - contentPadding: const EdgeInsets.only(left: 16.0, right: 12.0), - title: Text(tr("list_tile.show_people_labels.title")), - value: storyTilePreferences.showPeopleLabels, - onChanged: (value) { - storyTilePreferences = storyTilePreferences.copyWith(showPeopleLabels: value); - setState(() {}); - }, - ), - SwitchListTile.adaptive( - secondary: const SpSettingIconBadge(weekday: 4, icon: SpIcons.managingPage), - contentPadding: const EdgeInsets.only(left: 16.0, right: 12.0), - title: Text(tr("list_tile.show_page_count.title")), - value: storyTilePreferences.showPageCount, - onChanged: (value) { - storyTilePreferences = storyTilePreferences.copyWith(showPageCount: value); - setState(() {}); - }, - ), - SwitchListTile.adaptive( - secondary: const SpSettingIconBadge(weekday: 5, icon: SpIcons.map), - contentPadding: const EdgeInsets.only(left: 16.0, right: 12.0), - title: Text(tr("list_tile.show_location.title")), - value: storyTilePreferences.showLocation, - onChanged: (value) { - storyTilePreferences = storyTilePreferences.copyWith(showLocation: value); - setState(() {}); - }, - ), - _CharacterCountSlider( - preferences: storyTilePreferences, - onChanged: (value) { - storyTilePreferences = storyTilePreferences.copyWith(displayCharacterCount: value); - setState(() {}); - }, + Container( + margin: const EdgeInsets.symmetric(horizontal: 16.0), + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + border: Border.all(color: Theme.of(context).dividerColor), + borderRadius: BorderRadius.circular(12.0), + ), + child: SizedBox( + height: 240, + child: Scrollbar( + controller: _optionsScrollController, + thumbVisibility: true, + child: ListView( + controller: _optionsScrollController, + padding: const EdgeInsets.symmetric(vertical: 8.0), + children: [ + SwitchListTile.adaptive( + secondary: const SpSettingIconBadge(weekday: 7, icon: SpIcons.photo), + contentPadding: const EdgeInsets.only(left: 16.0, right: 14.0), + title: Text(tr("list_tile.photo_collage.title")), + value: storyTilePreferences.photoCollage, + onChanged: (value) => _apply(storyTilePreferences.copyWith(photoCollage: value)), + ), + SwitchListTile.adaptive( + secondary: const SpSettingIconBadge(weekday: 1, icon: SpIcons.timer), + contentPadding: const EdgeInsets.only(left: 16.0, right: 14.0), + title: Text(tr("list_tile.show_time.title")), + value: storyTilePreferences.showTime, + onChanged: (value) => _apply(storyTilePreferences.copyWith(showTime: value)), + ), + SwitchListTile.adaptive( + secondary: const SpSettingIconBadge(weekday: 2, icon: SpIcons.voice), + contentPadding: const EdgeInsets.only(left: 16.0, right: 14.0), + title: Text(tr("list_tile.show_voice_count.title")), + value: storyTilePreferences.showVoiceCount, + onChanged: (value) => _apply(storyTilePreferences.copyWith(showVoiceCount: value)), + ), + SwitchListTile.adaptive( + secondary: const SpSettingIconBadge(weekday: 3, icon: SpIcons.tag), + contentPadding: const EdgeInsets.only(left: 16.0, right: 14.0), + title: Text(tr("list_tile.show_tag_labels.title")), + value: storyTilePreferences.showTagLabels, + onChanged: (value) => _apply(storyTilePreferences.copyWith(showTagLabels: value)), + ), + SwitchListTile.adaptive( + secondary: const SpSettingIconBadge(weekday: 4, icon: SpIcons.alternateEmail), + contentPadding: const EdgeInsets.only(left: 16.0, right: 14.0), + title: Text(tr("list_tile.show_people_labels.title")), + value: storyTilePreferences.showPeopleLabels, + onChanged: (value) => _apply(storyTilePreferences.copyWith(showPeopleLabels: value)), + ), + SwitchListTile.adaptive( + secondary: const SpSettingIconBadge(weekday: 5, icon: SpIcons.managingPage), + contentPadding: const EdgeInsets.only(left: 16.0, right: 14.0), + title: Text(tr("list_tile.show_page_count.title")), + value: storyTilePreferences.showPageCount, + onChanged: (value) => _apply(storyTilePreferences.copyWith(showPageCount: value)), + ), + SwitchListTile.adaptive( + secondary: const SpSettingIconBadge(weekday: 6, icon: SpIcons.map), + contentPadding: const EdgeInsets.only(left: 16.0, right: 14.0), + title: Text(tr("list_tile.show_location.title")), + value: storyTilePreferences.showLocation, + onChanged: (value) => _apply(storyTilePreferences.copyWith(showLocation: value)), + ), + _CharacterCountSlider( + preferences: storyTilePreferences, + onChanged: (value) => _apply(storyTilePreferences.copyWith(displayCharacterCount: value)), + ), + ], + ), + ), + ), ), const SizedBox(height: 16.0), SpSectionTitle(title: tr("general.preview")), @@ -366,8 +423,8 @@ class _CharacterCountSliderState extends State<_CharacterCountSlider> { crossAxisAlignment: CrossAxisAlignment.start, children: [ ListTile( - contentPadding: const EdgeInsets.only(left: 16.0, right: 24.0), - leading: const SpSettingIconBadge(weekday: 6, icon: SpIcons.text), + contentPadding: const EdgeInsets.only(left: 16.0, right: 32.0), + leading: const SpSettingIconBadge(weekday: 1, icon: SpIcons.text), title: Text(tr("list_tile.preview_char_count.title")), trailing: Text( _localValue.toString(), @@ -377,7 +434,7 @@ class _CharacterCountSliderState extends State<_CharacterCountSlider> { ), ), Container( - padding: const EdgeInsets.symmetric(horizontal: 16.0), + padding: const EdgeInsets.symmetric(horizontal: 32.0), child: Slider.adaptive( value: _localValue.toDouble(), min: 50, diff --git a/lib/widgets/story_list/local_widgets/story_tile_contents.dart b/lib/widgets/story_list/local_widgets/story_tile_contents.dart index c7deede0..bab703b4 100644 --- a/lib/widgets/story_list/local_widgets/story_tile_contents.dart +++ b/lib/widgets/story_list/local_widgets/story_tile_contents.dart @@ -21,6 +21,14 @@ class _StoryTileContents extends StatelessWidget { final String? displayShortBody; final StoryTilePreferencesObject preferences; + void _viewAssetImageAt(BuildContext context, List imagePaths, int index) { + SpImagesViewer.fromString( + images: imagePaths, + initialIndex: index, + context: context, + ).show(context); + } + @override Widget build(BuildContext context) { // display only images for now. @@ -70,7 +78,16 @@ class _StoryTileContents extends StatelessWidget { ), if (assetPaths?.isNotEmpty == true) ...[ SizedBox(height: MediaQuery.textScalerOf(context).scale(6)), - _StoryTileAssets(assetPaths: assetPaths!), + if (preferences.photoCollage) + ConstrainedBox( + constraints: BoxConstraints(maxWidth: MediaQuery.textScalerOf(context).scale(240)), + child: SpAlbumGrid( + paths: assetPaths!, + onTap: viewOnly ? null : (index) => _viewAssetImageAt(context, assetPaths, index), + ), + ) + else + _StoryTileAssets(assetPaths: assetPaths!), SizedBox(height: MediaQuery.textScalerOf(context).scale(4)), ], SpStoryLabels( diff --git a/lib/widgets/story_list/sp_story_tile.dart b/lib/widgets/story_list/sp_story_tile.dart index fe26591d..7794061c 100644 --- a/lib/widgets/story_list/sp_story_tile.dart +++ b/lib/widgets/story_list/sp_story_tile.dart @@ -15,6 +15,7 @@ import 'package:storypad/core/helpers/date_format_helper.dart'; import 'package:storypad/providers/device_preferences_provider.dart'; import 'package:storypad/widgets/bottom_sheets/sp_story_info_sheet.dart'; import 'package:storypad/widgets/sp_icons.dart'; +import 'package:storypad/widgets/sp_album_grid.dart'; import 'package:storypad/widgets/sp_image.dart'; import 'package:storypad/widgets/sp_animated_icon.dart'; import 'package:storypad/widgets/sp_images_viewer.dart'; diff --git a/translations/ar.json b/translations/ar.json index 6aa75fe0..f5fff1ff 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "تم النقل إلى سلة المهملات", "list_tile.period_calendar.subtitle": "تتبع دورتك ومشاعرك", "list_tile.period_calendar.title": "تقويم الدورة الشهرية", + "list_tile.photo_collage.title": "صورة مجمعة", "list_tile.preview_char_count.title": "عدد الأحرف في المعاينة", "list_tile.product_hunt.title": "صوّت لنا على {ARG_NAME}", "list_tile.rate_on_store.title": "قيّمونا على {ARG_NAME}", diff --git a/translations/de-DE.json b/translations/de-DE.json index 964a4e0a..2b355fc2 100644 --- a/translations/de-DE.json +++ b/translations/de-DE.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "In den Papierkorb verschoben", "list_tile.period_calendar.subtitle": "Verfolgen Sie Ihren Zyklus und Ihre Gefühle", "list_tile.period_calendar.title": "Menstruationskalender", + "list_tile.photo_collage.title": "Fotocollage", "list_tile.preview_char_count.title": "Vorschau Zeichenanzahl", "list_tile.product_hunt.title": "Gib uns ein Upvote auf {ARG_NAME}", "list_tile.rate_on_store.title": "Bewerten Sie uns auf {ARG_NAME}", diff --git a/translations/en.json b/translations/en.json index 7d54354b..58bf1280 100644 --- a/translations/en.json +++ b/translations/en.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "Moved to bin", "list_tile.period_calendar.subtitle": "Track your cycle and feelings", "list_tile.period_calendar.title": "Period Calendar", + "list_tile.photo_collage.title": "Photo Collage", "list_tile.preview_char_count.title": "Preview Character Count", "list_tile.product_hunt.title": "Upvote us on {ARG_NAME}", "list_tile.rate_on_store.title": "Rate us on {ARG_NAME}", diff --git a/translations/es-419.json b/translations/es-419.json index dbae05c9..0ce40a97 100644 --- a/translations/es-419.json +++ b/translations/es-419.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "Movido a la papelera", "list_tile.period_calendar.subtitle": "Sigue tu ciclo y tus sentimientos", "list_tile.period_calendar.title": "Calendario menstrual", + "list_tile.photo_collage.title": "Collage de fotos", "list_tile.preview_char_count.title": "Vista previa del recuento de caracteres", "list_tile.product_hunt.title": "Vota a favor de nosotros en {ARG_NAME}", "list_tile.rate_on_store.title": "Califícanos en {ARG_NAME}", diff --git a/translations/es-ES.json b/translations/es-ES.json index 529a82fe..5939fcda 100644 --- a/translations/es-ES.json +++ b/translations/es-ES.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "Movido a la papelera", "list_tile.period_calendar.subtitle": "Sigue tu ciclo y tus sentimientos", "list_tile.period_calendar.title": "Calendario menstrual", + "list_tile.photo_collage.title": "Collage de fotos", "list_tile.preview_char_count.title": "Vista previa del recuento de caracteres", "list_tile.product_hunt.title": "Vota a favor de nosotros en {ARG_NAME}", "list_tile.rate_on_store.title": "Califícanos en {ARG_NAME}", diff --git a/translations/fr-FR.json b/translations/fr-FR.json index ec482482..5e3fca8e 100644 --- a/translations/fr-FR.json +++ b/translations/fr-FR.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "Déplacé vers la corbeille", "list_tile.period_calendar.subtitle": "Suivez votre cycle et vos sentiments", "list_tile.period_calendar.title": "Calendrier menstruel", + "list_tile.photo_collage.title": "Collage photo", "list_tile.preview_char_count.title": "Nombre de caractères d'aperçu", "list_tile.product_hunt.title": "Votez pour nous sur {ARG_NAME}", "list_tile.rate_on_store.title": "Évaluez-nous sur {ARG_NAME}", diff --git a/translations/hi-IN.json b/translations/hi-IN.json index a2a87b00..460d222e 100644 --- a/translations/hi-IN.json +++ b/translations/hi-IN.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "बिन में ले जाया गया", "list_tile.period_calendar.subtitle": "अपने चक्र और भावनाओं पर नज़र रखें", "list_tile.period_calendar.title": "मासिक धर्म कैलेंडर", + "list_tile.photo_collage.title": "फोटो कोलाज़", "list_tile.preview_char_count.title": "वर्णों की संख्या का पूर्वावलोकन", "list_tile.product_hunt.title": "{ARG_NAME} पर हमें अपवोट करें", "list_tile.rate_on_store.title": "हमें {ARG_NAME} पर रेट करें", diff --git a/translations/id.json b/translations/id.json index ece66bda..bd0d1417 100644 --- a/translations/id.json +++ b/translations/id.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "Dipindahkan ke tempat sampah", "list_tile.period_calendar.subtitle": "Lacak siklus dan perasaan Anda", "list_tile.period_calendar.title": "Kalender Menstruasi", + "list_tile.photo_collage.title": "Kolase Foto", "list_tile.preview_char_count.title": "Pratinjau Jumlah Karakter", "list_tile.product_hunt.title": "Beri kami upvote di {ARG_NAME}", "list_tile.rate_on_store.title": "Beri kami peringkat di {ARG_NAME}", diff --git a/translations/it-IT.json b/translations/it-IT.json index ef0c1e5d..8042b524 100644 --- a/translations/it-IT.json +++ b/translations/it-IT.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "Spostato nel cestino", "list_tile.period_calendar.subtitle": "Tieni traccia del tuo ciclo e delle tue sensazioni", "list_tile.period_calendar.title": "Calendario mestruale", + "list_tile.photo_collage.title": "Collage fotografico", "list_tile.preview_char_count.title": "Anteprima del conteggio dei caratteri", "list_tile.product_hunt.title": "Votaci su {ARG_NAME}", "list_tile.rate_on_store.title": "Valutaci su {ARG_NAME}", diff --git a/translations/ja-JP.json b/translations/ja-JP.json index 02348709..d9786915 100644 --- a/translations/ja-JP.json +++ b/translations/ja-JP.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "ゴミ箱に移動しました", "list_tile.period_calendar.subtitle": "周期と感情を追跡する", "list_tile.period_calendar.title": "月経カレンダー", + "list_tile.photo_collage.title": "フォトコラージュ", "list_tile.preview_char_count.title": "プレビュー文字数", "list_tile.product_hunt.title": "{ARG_NAME}で私たちに賛成票をお願いします", "list_tile.rate_on_store.title": "{ARG_NAME}で評価してください。", diff --git a/translations/km.json b/translations/km.json index ebed8020..4b9d0115 100644 --- a/translations/km.json +++ b/translations/km.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "ផ្លាស់ទីទៅធុងសំរាម", "list_tile.period_calendar.subtitle": "តាមដានវដ្តនិងអារម្មណ៍របស់អ្នក។", "list_tile.period_calendar.title": "ប្រតិទិនរដូវ", + "list_tile.photo_collage.title": "រូបថត​ចម្រុះ", "list_tile.preview_char_count.title": "មើលជាមុនចំនួនតួអក្សរ", "list_tile.product_hunt.title": "បោះឆ្នោតគាំទ្រយើងលើ {ARG_NAME}", "list_tile.rate_on_store.title": "វាយតម្លៃយើងនៅលើ {ARG_NAME}", diff --git a/translations/ko-KR.json b/translations/ko-KR.json index 3fa0589c..65e8acf2 100644 --- a/translations/ko-KR.json +++ b/translations/ko-KR.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "휴지통으로 옮겨졌어요", "list_tile.period_calendar.subtitle": "주기와 감정을 추적하세요", "list_tile.period_calendar.title": "월경 달력", + "list_tile.photo_collage.title": "사진 콜라주", "list_tile.preview_char_count.title": "미리보기 문자 수", "list_tile.product_hunt.title": "{ARG_NAME}에서 저희를 추천해 주세요", "list_tile.rate_on_store.title": "{ARG_NAME}에서 저희를 평가해 주세요.", @@ -371,7 +372,7 @@ "page.import_export_backup": "데이터 가져오기/내보내기", "page.language.title": "언어", "page.library.empty_message": "항목이 여기에 표시됩니다.", - "page.library.title": "메디아", + "page.library.title": "미디어", "page.library.title_with_app_name": "스토리패드 미디어", "page.map.edit_place.recent_labels": "최근 라벨", "page.map.edit_place.title": "장소 이름 수정", diff --git a/translations/pl-PL.json b/translations/pl-PL.json index a3363d5f..57511167 100644 --- a/translations/pl-PL.json +++ b/translations/pl-PL.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "Przeniesiono do kosza", "list_tile.period_calendar.subtitle": "Śledź swój cykl i uczucia", "list_tile.period_calendar.title": "Kalendarz menstruacyjny", + "list_tile.photo_collage.title": "Kolaż zdjęć", "list_tile.preview_char_count.title": "Podgląd liczby znaków", "list_tile.product_hunt.title": "Zagłosuj na nas na {ARG_NAME}", "list_tile.rate_on_store.title": "Oceń nas na {ARG_NAME}", @@ -371,7 +372,7 @@ "page.import_export_backup": "Import/Eksport danych", "page.language.title": "Język", "page.library.empty_message": "Tutaj pojawią się elementy.", - "page.library.title": "Głoska bezdźwięczna", + "page.library.title": "Media", "page.library.title_with_app_name": "StoryPad Media", "page.map.edit_place.recent_labels": "Ostatnie etykiety", "page.map.edit_place.title": "Edytuj nazwę miejsca", diff --git a/translations/pt-BR.json b/translations/pt-BR.json index 5220e01d..8cb7c720 100644 --- a/translations/pt-BR.json +++ b/translations/pt-BR.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "Movido para a lixeira", "list_tile.period_calendar.subtitle": "Acompanhe seu ciclo e seus sentimentos", "list_tile.period_calendar.title": "Calendário menstrual", + "list_tile.photo_collage.title": "Colagem de fotos", "list_tile.preview_char_count.title": "Contagem de caracteres de pré-visualização", "list_tile.product_hunt.title": "Vote a favor de nós em {ARG_NAME}", "list_tile.rate_on_store.title": "Avalie-nos em {ARG_NAME}", @@ -365,14 +366,14 @@ "page.home.app_bar.messages.what_in_ur_mind": "O que está em sua mente?", "page.home.empty_message": "Clique em {EDIT_BUTTON} para adicionar uma história a {YEAR}.", "page.home.story_recap.active_days": "{SP_ACTIVE} de {SP_TOTAL} dias", - "page.home.story_recap.title": "Resumo do mês de SP", + "page.home.story_recap.title": "Destaques de {SP_MONTH}", "page.home.title": "Lar", "page.image_picker.empty_message": "As fotos adicionadas aparecerão aqui.", "page.import_export_backup": "Dados de importação/exportação", "page.language.title": "Linguagem", "page.library.empty_message": "Os itens aparecerão aqui.", "page.library.title": "Mídia", - "page.library.title_with_app_name": "StoryPad Media", + "page.library.title_with_app_name": "StoryPad Mídia", "page.map.edit_place.recent_labels": "Rótulos recentes", "page.map.edit_place.title": "Editar nome do local", "page.map.picker.messages.drag_map_to_select_place": "Arraste o mapa para selecionar um local.", @@ -444,7 +445,7 @@ "plural.day_ago.one": "1 dia atrás", "plural.day_ago.other": "{} dias atrás", "plural.entry.one": "1 entrada", - "plural.entry.other": "entradas {}", + "plural.entry.other": "{} entradas", "plural.page.one": "1 página", "plural.page.other": "{} páginas", "plural.photo.one": "1 foto", diff --git a/translations/ru-RU.json b/translations/ru-RU.json index 8e4c74ab..e43a0b71 100644 --- a/translations/ru-RU.json +++ b/translations/ru-RU.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "Перемещено в корзину", "list_tile.period_calendar.subtitle": "Следите за циклом и своими чувствами.", "list_tile.period_calendar.title": "Календарь менструаций", + "list_tile.photo_collage.title": "Фотоколлаж", "list_tile.preview_char_count.title": "Предварительный просмотр количества символов", "list_tile.product_hunt.title": "Проголосуйте за нас на {ARG_NAME}", "list_tile.rate_on_store.title": "Оцените нас на {ARG_NAME}", diff --git a/translations/th-TH.json b/translations/th-TH.json index b7562a30..43232b2e 100644 --- a/translations/th-TH.json +++ b/translations/th-TH.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "ย้ายไปถังขยะ", "list_tile.period_calendar.subtitle": "ติดตามรอบเดือนและความรู้สึกของคุณ", "list_tile.period_calendar.title": "ปฏิทินช่วงเวลา", + "list_tile.photo_collage.title": "ภาพตัดต่อ", "list_tile.preview_char_count.title": "จำนวนอักขระที่แสดงตัวอย่าง", "list_tile.product_hunt.title": "กดโหวตสนับสนุนเราบน {ARG_NAME}", "list_tile.rate_on_store.title": "ให้คะแนนเราบน {ARG_NAME}", diff --git a/translations/tr.json b/translations/tr.json index 85cf95ca..9def66bf 100644 --- a/translations/tr.json +++ b/translations/tr.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "Çöp kutusuna taşındı.", "list_tile.period_calendar.subtitle": "Adet döngünüzü ve hislerinizi takip edin.", "list_tile.period_calendar.title": "Adet Takvimi", + "list_tile.photo_collage.title": "Fotoğraf Kolajı", "list_tile.preview_char_count.title": "Karakter Sayısı Önizlemesi", "list_tile.product_hunt.title": "Bizi {ARG_NAME} üzerinden oylayın.", "list_tile.rate_on_store.title": "Bizi {ARG_NAME} üzerinden değerlendirin.", @@ -444,11 +445,11 @@ "plural.day_ago.one": "1 gün önce", "plural.day_ago.other": "{} gün önce", "plural.entry.one": "1 giriş", - "plural.entry.other": "{} girişler", + "plural.entry.other": "{} giriş", "plural.page.one": "1 sayfa", "plural.page.other": "{} sayfa", "plural.photo.one": "1 fotoğraf", - "plural.photo.other": "{} fotoğraflar", + "plural.photo.other": "{} fotoğraf", "plural.row.one": "1 satır", "plural.row.other": "{} satır", "plural.voice.one": "1 ses", diff --git a/translations/uk-UA.json b/translations/uk-UA.json index 0b1a3ad2..56ee4e79 100644 --- a/translations/uk-UA.json +++ b/translations/uk-UA.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "Переміщено до кошика", "list_tile.period_calendar.subtitle": "Відстежуйте свій цикл і самопочуття", "list_tile.period_calendar.title": "Календар менструальних періодів", + "list_tile.photo_collage.title": "Фотоколаж", "list_tile.preview_char_count.title": "Попередній перегляд кількості символів", "list_tile.product_hunt.title": "Проголосуйте за нас на {ARG_NAME}", "list_tile.rate_on_store.title": "Оцініть нас на {ARG_NAME}", diff --git a/translations/vi-VN.json b/translations/vi-VN.json index eb0f206c..0c84a9c1 100644 --- a/translations/vi-VN.json +++ b/translations/vi-VN.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "Đã chuyển vào thùng rác", "list_tile.period_calendar.subtitle": "Theo dõi chu kỳ và cảm xúc của bạn", "list_tile.period_calendar.title": "Lịch kinh nguyệt", + "list_tile.photo_collage.title": "Ảnh ghép", "list_tile.preview_char_count.title": "Số ký tự xem trước", "list_tile.product_hunt.title": "Hãy bình chọn cho chúng tôi trên {ARG_NAME}", "list_tile.rate_on_store.title": "Đánh giá chúng tôi trên {ARG_NAME}", diff --git a/translations/zh-CN.json b/translations/zh-CN.json index 16da1b1b..7f3abf75 100644 --- a/translations/zh-CN.json +++ b/translations/zh-CN.json @@ -290,6 +290,7 @@ "list_tile.moved_to_bin_at.title": "已移至垃圾箱", "list_tile.period_calendar.subtitle": "追踪你的周期和感受", "list_tile.period_calendar.title": "经期日历", + "list_tile.photo_collage.title": "照片拼贴画", "list_tile.preview_char_count.title": "预览字符数", "list_tile.product_hunt.title": "请在 {ARG_NAME} 上为我们点赞", "list_tile.rate_on_store.title": "请在 {ARG_NAME} 上给我们评分", @@ -372,7 +373,7 @@ "page.language.title": "语言", "page.library.empty_message": "物品将显示在此处。", "page.library.title": "媒体", - "page.library.title_with_app_name": "StoryPad Media", + "page.library.title_with_app_name": "StoryPad 媒体", "page.map.edit_place.recent_labels": "近期标签", "page.map.edit_place.title": "编辑地名", "page.map.picker.messages.drag_map_to_select_place": "拖动地图选择位置",