LoginSignup
0
0

読書専用アプリの作成

Last updated at Posted at 2023-05-19

概要

読書に特化したアプリケーションを作成しています。

機能

登録、閲覧、削除、更新の機能を実装したいと考えています。現在完了しているのは閲覧、削除です。
https://jamboard.google.com/d/1Z7IRT7GP2ROn3AlAZVQAdSLEE5osza84ZYLpopTPV0M/edit?usp=sharing

動作確認

java

MainActivity.java

package com.example.app19;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Bundle;
import android.view.View;

import java.util.ArrayList;
import java.util.List;
import android.content.Intent;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {


    public static final String EXTRA_PAN = BuildConfig.APPLICATION_ID + ".PAN";     // 本情報を送るときに使用するEXTRA名用定数
    private List<book> bookList;        // BOOK(データ)
    private RecyclerView recycler;    // リサイクラービュー
    private book.Adapter adapter;      // アダプター

    public static final String EXTRA_TITLE = BuildConfig.APPLICATION_ID + ".TITLE";   // Extraに使う用の定数を用意
    public static final String EXTRA_WHY01 = BuildConfig.APPLICATION_ID + ".WHY01";     // Extraに使う用の定数を用意



    private ActivityResultLauncher<Intent> settingLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
            new ActivityResultCallback<ActivityResult>() {  // 2つ目の引数で結果を受け取った時の処理(インタフェースを定義)
                @Override
                public void onActivityResult(ActivityResult result) {
                    if(result.getResultCode() == RESULT_OK) {   // 結果がRESULT_OK(成功)の場合
                        Intent intent = result.getData();       // result.getData()により結果のインテント取得
                        p2_title = intent.getStringExtra(EXTRA_TITLE);   // intentから上で定義したEXTRA_NAME(com.example.app14.NAME)という名前のデータをStringで取得
                        p2_why01 = intent.getStringExtra(EXTRA_WHY01);

                    }
                }
            }
    );
    int p2_num;
    private String p2_title;
    private String p2_why01;
    private String p2_why02;
    private String p2_why03;
    private String p2_about;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bookList = new ArrayList<>();                    // BOOKリストを初期化

//単語帳機能・・学習した単語を登録しテストできる機能(記憶の定着を高めるため一日、1週間、1か月のスパンでテストする)


        book p1 =  new book (R.drawable.book, 1," 読書方法", " 効果的な読書の仕方をしりたっかた", " 本の読み方ノウハウを知りたいから", "今後、積極的に本を読むようになりたいまた人生の幸福度を上げたい", " 目次 \n" +
                "本を読む前の準備 \n" +
                " ・内容を予測する(間違っても大丈夫)\n" +
                " ・同じジャンルの本を複数読む(共通点がわかる) \n" +
                " ・内容を予測する(間違っても大丈夫) \n" +
                "読書中に意識すること \n" +
                " ・読みたい章から読むこと \n" +
                " ・すべてを読むのではなく、「しかし」「つまり」文の終わりつまり筆者が言いたいことを重点的に読む(全体の20%) \n" +
                " ・内容に質問しながら読む(例)なぜ筆者はそう思ったのか?言いたいことは何なのか? \n" +
                " ・一旦本を閉じ学習した内容をまとめる \n" +
                " ・知っている内容と知らない内容の差を意識する \n" +
                " ・要約しながら読む(予測とのギャップを意識) \n" +
                "読み終えた時にすること(アウトプット) \n" +
                " ・忘れている事を思い出す訓練 \n" +
                " ・人に説明する \n" +
                " ・学んだ事を体を使って実践してみる \n" +
                " 違う方法で三回アウトプットしてみる");

                 p2_num=2;
                 p2_title="";
                 p2_why01="";
                 p2_why02="";
                 p2_why03="";
                 p2_about="";



            book p2 =  new book (R.drawable.book,p2_num,p2_title, p2_why01, p2_why02, p2_why03, p2_about);

        // 追加機能の編集


        bookList.add(p1);
        bookList.add(p2);




        recycler = findViewById(R.id.recycler);
        recycler.setLayoutManager(new LinearLayoutManager(this));   // リストの表示形式を縦並びに設定
        adapter = new book.Adapter( bookList );                                 // 本リストを基にアダプターを生成
        recycler.setAdapter(adapter);                                       // リサイクラーにアダプターをセット


//

        findViewById(R.id.new_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Intent intent = new Intent(MainActivity.this, NewAdd.class);  // RegisterActivityを作っていない場合エラー
                startActivity(intent);
                }
        });
    }

}

book.java

package com.example.app19;

import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

import android.os.Parcel;
import android.os.Parcelable;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.List;

public class book implements Parcelable {


    private int imageRes;       // 本のイメージリソース
    private int num;            // 番号
    private String title;       // 自作タイトル
    private String why01;       // 事前準備1
    private String why02;       // 事前準備2
    private String why03;       // 事前準備3
    private String about;       // 内容

    //本情報初期化用コンストラクタ
    book(int imageRes, int num, String title, String why01, String why02, String why03, String about) {
        this.imageRes = imageRes;
        this.num = num;
        this.title = title;
        this.why01 = why01;
        this.why02 = why02;
        this.why03 = why03;
        this.about = about;
    }

    // 各種ゲッター

    public int getImageRes() {
        return imageRes;
    }
    public int getNum() {
        return num;
    }

    public String getTitle() {
        return title;
    }

    public String getWhy01() {
        return why01;
    }

    public String getWhy02() {
        return why02;
    }
    public String getWhy03() {
        return why03;
    }
    public String getAbout() {
        return about;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(imageRes);
        dest.writeInt(num);
        dest.writeString(title);
        dest.writeString(why01);
        dest.writeString(why02);
        dest.writeString(why03);
        dest.writeString(about);
    }

    //
    public static final Creator<book> CREATOR = new Creator<book>() {
        @Override
        public book createFromParcel(Parcel source) {
            int imageRes = source.readInt();
            int num = source.readInt();
            String title = source.readString();
            String why01 = source.readString();
            String why02 = source.readString();
            String why03 = source.readString();
            String about = source.readString();

            book book = new book (imageRes,num, title, why01,why02,why03, about);
            return book;
        }

        @Override
        public book[] newArray(int size) {
            return new book[0];
        }
    };

    // リスト1件分のViewをまとめるViewHolder


    public static class ViewHolder extends RecyclerView.ViewHolder {

        protected View rowView;         // 1件分のレイアウトView(クリック処理を実装する用)
        protected TextView title;       // 自作タイトルの表示用
        protected Button deleteBtn;     // 1件分のデータを削除するようボタン
        protected Button editBtn;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            rowView = itemView;     // itemView自体を保存(実体は、layout_book_row の LinearLayoutとなる)
            title = itemView.findViewById(R.id.title);
            deleteBtn = itemView.findViewById(R.id.delete_btn);

            editBtn = itemView.findViewById(R.id.edit_btn);
        }

        public View getRowView() {
            return rowView;
        }

        public TextView getTitle() {
            return title;
        }

        public Button getDeleteBtn() {
            return deleteBtn;
        }
        public Button getEditBtn() {
            return editBtn;
        }
    }

    // データとViewHolderを紐づけるAdapterクラス
    public static class Adapter extends RecyclerView.Adapter<ViewHolder> {

        private List<book> bookList;    // 本のリスト

        // 本リストを受け取る用のコンストラクタ
        public Adapter(List<book> bookList) {
            this.bookList = bookList;
        }

        // ViewHolder生成用メソッド
        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            // LayoutInflaterを使用し、layout_pan_rowを生成し、ViewHolderの生成も同時に行っている。
            return new ViewHolder(
                    LayoutInflater
                            .from(parent.getContext())
                            .inflate(R.layout.layout_book_row, parent, false));
        }

        // データとViewHolderの紐づけ用メソッド(リストがスクロールされ表示されるデータが切り替わるたびに呼ばれる)
        @Override
        public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
            final book book = bookList.get(position);  // 表示する本のデータを取得
            holder.getTitle().setText( book.getTitle());    // 本の名前をViewに設定

            // 削除ボタンを押したときの挙動を定義 notifyItemInserted()
            holder.getDeleteBtn().setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    bookList.remove(holder.getAdapterPosition());        // BOOKリストから本の情報を削除
                    notifyItemRemoved(holder.getAdapterPosition());     // リストの数が変更されたことを通知
                }
            });

            holder.getEditBtn().setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(v.getContext(), EditDetail.class);    // BookDetailActivityに遷移するためのIntent作成
                    intent.putExtra(MainActivity.EXTRA_PAN, book );                           // Intentにクリックし本の情報を設定
                    v.getContext().startActivity(intent);                                   // アクティビティを起動
                }
            });

            // 1件分のデータがクリックされた時の挙動を定義

            holder.getRowView().setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(v.getContext(), BookDetailActivity.class);    // PanDetailActivityに遷移するためのIntent作成
                    intent.putExtra(MainActivity.EXTRA_PAN, book );                           // Intentにクリックし本の情報を設定
                    v.getContext().startActivity(intent);                                   // アクティビティを起動
                }
            });

        }

        // リストのデータ数を返却するメソッド
        @Override
        public int getItemCount() {
            return bookList.size();
        }
    }

}


BookDetaukActivity

package com.example.app19;

import android.content.Intent;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

public class BookDetailActivity extends AppCompatActivity {

    private book book;    // 送信されてきたパン情報

    //編集画面

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_book_detail );

        Intent intent = getIntent();    // アクティビティの軌道に使われたIntent取得
        book = (book)intent.getParcelableExtra(MainActivity.EXTRA_PAN); // IntentからPan情報を取得

        ImageView image = findViewById(R.id.image);
        TextView titleText = findViewById(R.id.title);
        TextView why01Text = findViewById(R.id.why01);
        TextView why02Text = findViewById(R.id.why02);
        TextView why03Text = findViewById(R.id.why03);
        TextView About = findViewById(R.id.about);

        TextView num = findViewById(R.id.num);

        // 本情報をViewに設定
        image.setImageResource( book.getImageRes());
        titleText.setText( book.getTitle());
        why01Text.setText( book.getWhy01());
        why02Text.setText( book.getWhy02());
        why03Text.setText( book.getWhy03());
        About.setText( book.getAbout());
        num.setText(Integer.toString( book.getNum()));
        //num.setText(toString(book.getNum()));

    }

}



EditDitailActivity

package com.example.app19;

import android.content.Intent;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.EditText;
import android.widget.Button;
import android.view.View;

import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

public class EditDetail extends AppCompatActivity {

    private book book;    // 送信されてきた本情報
    private int number;

    //編集画面

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.edit_detail);

        Intent intent = getIntent();    // アクティビティの軌道に使われたIntent取得
        book = (book)intent.getParcelableExtra(MainActivity.EXTRA_PAN); // IntentからPan情報を取得

        ImageView image = findViewById(R.id.image);

        final EditText edit_titleText = findViewById(R.id.edit_title);
        final EditText edit_why01Text = findViewById(R.id.edit_why01);
        EditText edit_why02Text = findViewById(R.id.edit_why02);
        EditText edit_why03Text = findViewById(R.id.edit_why03);
        EditText edit_About = findViewById(R.id.edit_about);

        Button EditBtn = findViewById(R.id.edit_btn);


        //本情報をViewに設定
        image.setImageResource( book.getImageRes());
        edit_titleText.setText( book.getTitle());
        edit_why01Text.setText( book.getWhy01());
        edit_why02Text.setText( book.getWhy02());
        edit_why03Text.setText( book.getWhy03());
        edit_About.setText( book.getAbout());

        number=book.getNum();

        EditBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(edit_titleText.getText().toString().equals("")) {  // 未入力ならトーストを表示しonClick()を終了(return)
                    Toast.makeText(EditDetail.this, "titleを入力してください", Toast.LENGTH_SHORT).show();
                    return;
                }
                if(edit_why01Text.getText().toString().equals("")) {   // 未入力ならトーストを表示しonClick()を終了(return)
                    Toast.makeText(EditDetail.this, "01を入力してください", Toast.LENGTH_SHORT).show();
                    return;
                }

                Intent intent = new Intent();   // 空のインテント(行先の指定なし)を作成
                intent.putExtra(MainActivity.EXTRA_TITLE, edit_titleText.getText().toString());                    // MainActivityで定義したEXTRA_NAMEで、入力された名前を設定
                intent.putExtra(MainActivity.EXTRA_WHY01, edit_why01Text.getText().toString());    // MainActivityで定義したEXTRA_NAMEで、入力された年齢を設定
                //intent.putExtra(MainActivity.EXTRA_WHY01, Integer.parseInt(ageEdit.getText().toString()));    // MainActivityで定義したEXTRA_NAMEで、入力された年齢を設定
                setResult(RESULT_OK, intent);   // アクティビティの結果をRESULT_OK(成功)と返却値をintentとして登録
                finish();                       // アクティビティを終了(結果をMainActivityに返却)
            }
        });


    }

}



NewAdd.java

package com.example.app19;

import android.content.Intent;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.EditText;

import android.view.View;
import android.widget.Button;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;

public class NewAdd  extends AppCompatActivity {

    //新規登録画面

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.new_add);



        ImageView image = findViewById(R.id.add_image);
        EditText AddTitleText = findViewById(R.id.add_title);
        EditText AddWhy01Text = findViewById(R.id.add_why01);
        EditText AddWhy02Text = findViewById(R.id.add_why02);
        EditText AddWhy03Text = findViewById(R.id.add_why03);
        EditText AddAbout = findViewById(R.id.add_about);

        Button AddBtn = findViewById(R.id.add_btn);


        findViewById(R.id.add_btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Intent intent = new Intent(NewAdd.this, MainActivity.class);  // RegisterActivityを作っていない場合エラー
                startActivity(intent);
            }
        });


    }
}


layout

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/new_btn" />



    <Button
        android:id="@+id/new_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:text="登録"
        android:textSize="24sp" />

</RelativeLayout>

edit_ditail.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/image"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:src="@drawable/pan_bour_bu_ru" />

        <EditText
            android:id="@+id/edit_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="自分でタイトルを決めるなら"
            android:textSize="24sp" />

        <EditText
            android:id="@+id/edit_why01"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="なぜ、この本を読もうと思ったのか"
            android:textSize="24sp" />

        <EditText
            android:id="@+id/edit_why02"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="この本から何を得たいのか"
            android:textSize="24sp" />

        <EditText
            android:id="@+id/edit_why03"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="この本を読んでどうなりたいか"
            android:textSize="24sp" />

        <Button
            android:id="@+id/edit_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="right"
            android:text="保存"
            android:textSize="24sp" />

        <EditText
            android:id="@+id/edit_about"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="top|left"

            android:text="メモ"
            android:textSize="24sp" />

    </LinearLayout>

</ScrollView>

layout_book_datail.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/image"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:src="@drawable/pan_bour_bu_ru" />

        <TextView
            android:id="@+id/title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="title"
            android:textSize="24sp" />

        <TextView
            android:id="@+id/why01"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="why01"
            android:textSize="24sp" />

        <TextView
            android:id="@+id/why02"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="why02"
            android:textSize="24sp" />

        <TextView
            android:id="@+id/why03"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="why03"
            android:textSize="24sp" />



            <TextView
                android:id="@+id/about"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="about"
                android:textSize="24sp" />


        <TextView
            android:id="@+id/num"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="about"
            android:textSize="24sp" />

    </LinearLayout>

</ScrollView>

layout_book_row.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:background="@drawable/border_bottom"
    android:padding="5dp"
    android:layout_margin="5dp"
    android:focusable="true"
    android:clickable="true" >

<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="8" />

<Button
android:id="@+id/delete_btn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="削除" />
    <Button
        android:id="@+id/edit_btn"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="2"
        android:text="編集" />

    </LinearLayout>

new_add.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/add_image"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:src="@drawable/pan_bour_bu_ru" />

        <EditText
            android:id="@+id/add_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="自分でタイトルを決めるなら"
            android:textSize="24sp" />

        <EditText
            android:id="@+id/add_why01"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="なぜ、この本を読もうと思ったのか"
            android:textSize="24sp" />

        <EditText
            android:id="@+id/add_why02"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="この本から何を得たいのか"
            android:textSize="24sp" />

        <EditText
            android:id="@+id/add_why03"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="この本を読んでどうなりたいか"
            android:textSize="24sp" />

        <Button
            android:id="@+id/add_btn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@id/add_why03"
            android:layout_gravity="right"
            android:text="保存"
            android:textSize="24sp" />

        <EditText
            android:id="@+id/add_about"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="top|left"
            android:hint="メモ"
            android:textSize="24sp" />


    </LinearLayout>


</ScrollView>

manufest

AndoroidoManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.app19">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".BookDetailActivity" /> //追加
        <activity android:name=".EditDetail" />     //追加
            <activity android:name=".NewAdd" />     //追加
    </application>

</manifest>

build.gradle(モジュール:app)

//省略
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    implementation 'androidx.appcompat:appcompat:1.3.1' //追加

    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

    implementation 'androidx.recyclerview:recyclerview:1.1.0'

    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0