Pull to refresh

TagToDo, Да еще одна ToDo-шка

Reading time5 min
Views1K

Мечта


У меня всегда была мечта написать «незабывайку». Множество раз я приступал к этой задаче, но либо желание пропадало на этапе макета, либо друзья говорили: «зачем на еще одина ToDo-шка, их итак миллион». Но желание написать что-то свое не пропадало. И вот на работе выдались относительно спокойные деньки, и я вновь задался темной целью: написать в конце концов свою «незабывайку». А так как я до селе работал только с десктопными приложениями, и в Web не зуб ногой, то решил совместить изучение и давнюю мечту. Учитывая, что основной мой хлеб это .Net + WPF. Я избрал платформой Silverlight. Вроде как и .Net + WPF, но что-то новенькое. Быстро поставил цель, и в идеале я должен был завершить в 5 дней.

У нас есть цель.


Цель проекта, основная идея: Быстро добавить задачу и навесить (быстро) на нее теги, и чтобы по тегам можно фильтровать! Все. Когда появляется очередная гениальная идея, тыкать ее носом в основную идею. И откладывать. Все идеи как им и положено, крутились в башке, постоянно размножаясь. Но мне удалось им противостоять. В этом мне помог план.

План таков.


1. Наваять прототип интерфейса за 1 день.
2. Сделать БД и закрыть ее за бизнес-слоем. (1 день)
3. В общем-то накодить и получить первую бету. (1 день)
4. Отстрел багов (2 дня)
План не бог весть какой, но я ему следовал. Прототип был нарисован в программе Kaxaml (до сих пор рисую прототипы в виде xaml кода, а не на бумажках или спец. программах), причем там я совершил первую свою ошибку, я рисовал прототип для WPF, а он от Silverlight отличается достаточно сильно. Позднее я довольно много мелочей переправлял, хотя на внешний вид они не повлияли.

Одежка


Итоговый вид почти не изменился:
image
Я не дизайнер, поэтому решил просто «слизать» интерфейс с различных мокапов iPhone. Хотя, я не являюсь поклонником(обладателем) этого телефона, но интерфейс мне очень нравится. Подробно этот этап описывать не буду, только основные проблемы. Первая и главная: Silverlight'овский Xaml не есть подмножество WPF-xaml, они жутко отличаются в деталях. На это уже ссылался dotCypress. Все хитрые анимации я делал через VisualStateManager, основная идея его видна, кстати, из названия: организация состояний контрола, и управление переходами между состояниями. Довольно удобно, но не привычно для тех кто игрался с триггерами в WPF.

А где у нас бизнес-логика?


Так как у меня уже есть небольшой хостинг под виндой и БД MS SQL 2008, базу по понятным причинам, я написал там. Хотя, чего я оправдываюсь, я всю жизнь свою работал только с базами от микрософта, и ни капли не жалею об этом. Вся тудушка влезла в одну табличку и 2 хранимые процедуры, одна из которых добавляла тудушку, если ее не было, обновляла если она была, и удаляла, если основной текст ее был пуст (Надо было делать 3 штуки, но тут я схалявил, 3% бизнес-логики БД не убили). Вторая хранимка просто получала список задача. В качестве ID задачи я взял дату ее создания. Памятуя о статье, бизнес слой полностью перенес в сервис (silverlight enabled service), к которому должна будет обращаться программа, все 97%. Изначально хотел дергать все хранимые процедуры «ручками», но решил себе напомнить замечательный Rsdn.Framework.Data. Поэтому все было написано через его. Сам класс задачи после навешивания на него атрибутов от Rsdn и WCF выглядел так:
[DataContract]
public class ToDo {
[MapField("id")]
[DataMember]
public DateTime Id { get; set; }

[MapField("text")]
[DataMember]
public string Text { get; set; }

[MapField("completed")]
[DataMember]
public bool Completed { get; set; }

[MapField("tags")]
[DataMember]
public string Tags { get; set; }

[MapField("parentid")]
[DataMember]
public DateTime? ParentId { get; set; }


[IgnoreDataMember]
[MapField("userid")]
public int UserId { get; set; }
}

ParentId, это намек на ту единственную идею, которая пробила мои защитные барьеры и была реализована позднее. (привет, gmail'у). Как мы видим, класс очень простой, но увешан атрибутами. Атрибуты вида [DataMember], намекают, что эти данные будут уходить Silverlight приложению, а [IgnoreDataMember] — соответственно, что не будут. [MapField(«XXX»)] — это отображение полей класса на поля записи в БД. Признаться, только вот из-за такой магии внутри Rsdn.Framework в свое время я и перешел на c#.

Основной ошибкой на этом этапе было создание своего велосипеда авторизации\регистрации пользователя, хотя есть готовые механизмы ASP.Net и прочего. Почему я не стал ими пользоваться, я не знаю. 80% всего кода и остальные дополнительные таблички были созданы только ради авторизации и регистрации… Я каюсь, но это так.

Код


Этот этап абсолютно неинтересен, тут обычный C# со своим framework, код пишется легко и быстро. Все здорово. Но как всегда есть и затыки. К примеру, когда «рестайлишь» (создаем новый style) различные элементы, их поведение вполне адекватно и вообще соответствует тому, что ты пишешь, но ListBox имеет досадный баг. Его дочерние элементы никак не хотят занимать всю ширину родителя, а занимают ровно столько, сколько им надо. Грязный хак их победил. Увы, не получилось чистого xaml-решения. Или, например, нету DoubleClick'а, это уже серьезно, но вполне решаемо.

Играем. Тестируем.


Как всегда это самый длинный этап, когда появляется множество гениальных идей, которые надо душить в зародыше. А так же всякие запутки с непонятками, которые надо исправлять. Вот на этом-то этапе мне и подкинули идею «как у Google». Сделать задачи иерархическими. Тут сразу появились хаки с Drag'n'Drop (о Drag'n'Drop в Silverlight я расскажу, если будет интересно, отдельно) и всякие нелогичности. Но вроде все побеждено, я гордо ставлю версию 1.0, и отдаю проект на суд общественности.

TagTodo. Судим.


Итак, описание чего же у меня получилось. Features.
1. Сохранение задач онлайн, возможность получить к ним доступ из любой точки.
2. На каждую задачу навешиваются теги, по которым потом можно фильтровать. Теги автоматически раскрашиваются, на основе содержимого. Теги можно удалять и таскать.
3. Задачи можно разбить на подзадачи, а те в свою очередь тоже. И располагать задачи в виде иерархии.
4. Весь список можно экспортировать в виде XML.
5. Скорость и простота. Когда вы пишете задачу, отделите от основного текста теги обратным слешем '\'. И по нажатию кнопки enter, задача добавится, а так же появятся набранные теги. Например «Вымыть слона\мойка, слон». Добавится задача «Вымыть слона», с двумя тегами «мойка» и «слон».
6. Чтобы добавить задачу как дочернюю, просто выделите будущего папу и начните имя задачи с обратного слеша '\'. Впрочем, никто потом не помешает сделать то же самое обычным перетаскиванием.
7. Забавный тег «время-деньги». Он будет писать вам сколько же времени прошло с создания этой задачи. (см. картинку выше)

Заходите, поиграйтесь. Вам потребуется Silverlight 3.
Сразу хочу предупредить. Экран регистрации довольно нелогичен, сказалось мало времени. Нажав на кнопку регистрации, вы дополнительно к своему имени и паролю сможете ввести почту. При повторном нажатии на эту кнопку — на почту (если все хорошо, логин не занят, почта такая есть и т.п.) уйдет ссылка с подтверждением. Как только вы подтвердите свою почту. Аккаунт будет разблокирован и вы сможете поиграться с тудушкой.

P.S. Мой первый топик на хабре, хотелось обелить ярлык (тег?) «июлята». Получилось или нет — судить вам. Идеи, улучшения приветствуются, хотя и своих полон мозг.
Tags:
Hubs:
Total votes 14: ↑8 and ↓6+2
Comments12

Articles