Help us understand the problem. What is going on with this article?

相手に強制的にお願いできるアプリを作った

はじめに

こんにちは!
そるとと申します。

普段は某IT企業でオープン系のシステム開発を行っていますが、個人で仕事で使っていない技術の習得のためにアプリ開発を行っております。

今まで何個かアプリを作りましたが、今回はその中でもちょっと力を入れたアプリの機能紹介、個人的にこだわった点、作ってみて感じたことを記事にしました。

どんなアプリ?

簡単に言えば「タスクを相手に送る」アプリです!

相手にして欲しいこと、お願い、メモなどなど相手に伝えたいことを指定した時間に相手に通知させることが出来ます。
※もちろんToDoアプリとして自分のタスクを登録することも出来ます。
iPhone X-XS-11 Pro – 19.png

フレームワーク等

  • ionic
  • capacitor
  • Firebase

機能紹介

①ユーザー登録・ログイン

このアプリでは、タスクを送信し合うためにユーザー登録をする必要がありました。
ユーザー登録といえばメールアドレス・パスワードなどを登録するのが一般的だと思いますが、それがめんどくさくてアプリを食わず嫌いされるのは嫌だなと思い、ユーザー名だけでアプリを始められるようにしました。

具体的にはFirebaseの匿名認証を使用しております。

firebase.auth().signInAnonymously();

グループ 765.png

②やること

サインイン・サインアップ後に最初に表示されるユーザーが登録したやること(タスク)を一覧で表示してくれる画面です。
友達になったユーザーから送られてきたタスクは誰から送られてきたかをリストの右側に表示しています。
また、実行したタスクはチェックを付けることが出来ます。
グループ 768.png

③友達追加

ユーザー同士が友達となってタスクを送信し合えるようになるためにQRコードを使って友達を追加できるようにしました。
※どちらか一方が友達に追加するともう一方の人にも自動的に追加されるようになっております。(Facebookみたいな?)

※前回イン○タみたいなQRコード共有の記事を投稿しましたが、その方法を知る前に作ったアプリだったのでこんなにダサいQRコードになっています・・・
しかも共有できないし・・・😂
次バージョンでの機能UP対象ですね。

グループ 766.png

主な使用技術

  • ngx-kjua
    QRコードの表示に使用しました。

  • dom-to-image & Photo Library
    保存ボタン押下でQRコードをフォトライブラリに保存するために使用しました。
    DOMをPNGに変換した後にフォトライブラリに保存しています。

DOM→PNG変換してフォトライブラリに保存例.ts
import domtoimage from 'dom-to-image-more';
import { PhotoLibrary } from '@ionic-native/photo-library/ngx';
import { ToastController } from '@ionic/angular';

export class MyQRCodeComponent implements OnInit {

  constructor(private photoLibrary: PhotoLibrary, 
              private toastController: ToastController) {
  }

  saveQR() {
    //QRコード取得
    const div = document.getElementById('container');
    //DOM→PNG変換してフォトライブラリに保存
    domtoimage.toPng(div).then((dataUrl) => {
      this.photoLibrary.requestAuthorization({
        "read": true,
        "write": true
      }).then(() => {
        this.photoLibrary.saveImage(dataUrl,'たのんだー').then(()=>{
          this.showToast("保存しました")
        }).catch((err) => {
          console.log(err);
          this.showToast("保存出来ませんでした")
        });
      }).catch((err) => {
        console.log(err);
        this.showToast("保存出来ませんでした")
      });
    });
  }

  async showToast(message) {
    const toast = await this.toastController.create({
      message: message,
      duration: 2000,
      color: "dark"
    });
    toast.present();
  }
}

④タスク作成・送信

タスクは自分用友達用の両方作成できるような画面にしました。
また、一回のみ毎日毎週毎月の4パターンで通知を任意で設定できるようにしました。

グループ 767.png

主な使用技術

  • Local Notifications
    通知の登録用に使いました。
    自分用のタスクはタスク追加時に通知の登録を行い、送られてきたタスクは受信時に通知の登録を行っております。
通知登録例.ts
import { LocalNotifications } from '@ionic-native/local-notifications/ngx';

export class MakeTaskPage implements OnInit {

  //やることデータ
  data: { title: string, memo: string, date: string, time: string, week: string } = { title: '', memo: '', date: '', time: '', week: '' };

  //通知種類
  notiKind: string = ""

  constructor(private localNotifications: LocalNotifications) {}

  //やること作成
  makeTask() {

    //******************* ~ なんやかんややること作成処理 ~ *******************//

    //通知ID取得処理
    const ID: string = this.getID();

    const choiceDate = new Date(this.data.date);
    const year: number = choiceDate.getFullYear();
    const month: number = choiceDate.getMonth();
    const dayOfWeek: number = choiceDate.getDay();
    const day: number = choiceDate.getDate();
    const choiceTime = new Date(this.data.time);
    const hour: number = choiceTime.getHours();
    const minute: number = choiceTime.getMinutes();

    switch (this.notiKind) {
    case "毎日":
      this.localNotifications.schedule({
        id: ID,
        title: this.data.title,
        text: this.data.memo,
        foreground: true,
        trigger: { every: { hour: hour, minute: minute } },
      });
      break;

    case "毎週":
      this.localNotifications.schedule({
        id: ID,
        title: this.data.title,
        text: this.data.memo,
        foreground: true,
        trigger: { every: { weekday: dayOfWeek, hour: hour, minute: minute } },
      });
      break;

    case "毎月":
      this.localNotifications.schedule({
        id: ID,
        title: this.data.title,
        text: this.data.memo,
        foreground: true,
        trigger: { every: { day: day, hour: hour, minute: minute } },
      });
      break;

    default:
      this.localNotifications.schedule({
        id: ID,
        title: this.data.title,
        text: this.data.memo,
        foreground: true,
        trigger: { at: new Date(year, month, day, hour, minute) },
      });
      break;
    }
  }
}

⑤その他機能

直近1週間のタスク送受信履歴やアカウント設定なども行えます。
グループ 769.png

こだわったところ

自分がこのアプリでこだわった部分についてご紹介します。
尚、こだわり前のUIは以下のような感じでした。
グループ 770.png

UI・フォント

UIは見やすさを重視して、背景とツールバー、タブバーを同一色にし、差し色で青を使うようにしました。これによって意味があるものがパッと見ですぐわかるということとなんとなくデザインが締まって見えるようになりました。
また、フォントは読みやすくて今っぽい丸めなフォントを探していました。ただ、実際あんまり丸過ぎると可愛くなってしまってユーザーを選んでしまう恐れがあったので絶妙な感じのMgen+ (ムゲンプラス)にしました。

難しくし過ぎない

最初は通知する時間をもっと細かい設定が出来るようにしていたのですが、利用者のことを考えるとある程度機能が制限されていても操作しやすい画面の方がいいのかなと思ったので4パターンで設定出来るようにしました。
また、アプリ名も上記にある通り、「Sentifer」という名前を仮で付けていたのですが、Sentiferっていう文字を見ても何ができるアプリなのかわかりづらいと思いましたので、「たのんだー」に変更しました。

プライバシー

友達をIDで検索する機能を付けようか考えましたが、自分のIDが流出して知らない人からたくさんタスクが届いても嫌だよなあと思い、知っている人だけにQRを渡して知り合い同士で使っていただけるような仕組みにしました。また、画像は載せていませんが、友達をブロック(受信拒否)する機能や通報できる機能なども実装しております。

まとめ

もっと簡単にすぐ完成すると思っていましたが、いろいろ考えながら作ると意外と時間がかかるということを感じました。あとは、個人開発は本当にモチベーションでその日の作業時間が決まってしまうのでずーっと高いモチベーションを維持するのが大変でした。でもなんだかんだありましたが1つの物として完成させることが出来たことは良い経験になりましたし、達成感がありました。

アプリのリンク

iOS
android

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away