likes
comments
collection
share

Flutter 日记App-添加日记本

作者站长头像
站长
· 阅读数 5

前言

根据上篇的效果图和方法,再同步封装一个支持开关按钮的Cell,便于日后开发。由于功能类似,组件差不多就不再赘述。这篇主要讲添加页的实现。

选项实现

首先在循环提醒中,是有三种选项的,选项为每天时仅展示两项,选项为每周或每月则展示三项。 选项的实现用上篇封装的SSLInputRow,选项弹窗目前采用系统自带的弹窗showTimePicker、showDatePicker和SimpleDialog。 具体实现如下:

//TODO: 选择月或周
  Future<int> showDayWithMonth(BuildContext context) async{
    if (cycleType == 2){
    //这里做判断,如果选择类型是周则弹周选项,如果是月则弹日历弹窗
      int? i = await showDialog<int>(
          context: context,
          builder: (BuildContext context){
            return SimpleDialog(
              alignment: Alignment.center,
              title: Text(SSLLocales.l_dream_cycle.tr),
              children: [
                SimpleDialogOption(
                  onPressed: (){
                    cycleTime = 1;
                    // warningCycleTimeStr = SSLLocales.l_dream_cycle_everyWeekOne.tr;
                    Get.back(result: 1);
                  },
                  child: Text(SSLLocales.l_dream_cycle_everyWeekOne.tr),
                ),
               ...重复的就不多加展示了
              ],
            );
          }
      );
      warningCycleTimeStr = SSLEngine.getWeekString(i??1);
      debugPrint("ssl select week $i");
    }else{
      DateTime? timed = await showDatePicker(
        context: context,
        initialDate: DateTime.now(),
        firstDate: DateTime(1990),
        lastDate: DateTime(2100),
        currentDate: DateTime.now(),
      );
      cycleTime = timed?.day ?? 1;
      warningCycleTimeStr = cycleTime.toString().padLeft(2,"0");
    }
    return cycleTime;
  }
//TODO: 选择当天时间
  Future<String?> showDefaultTimePicker(BuildContext context, DateTime? time) async {
    TimeOfDay? selectTime = await showTimePicker(
        context: context,
        initialTime: time != null ? TimeOfDay(hour: time.hour, minute: time.minute) : TimeOfDay.now()
    );
    if (selectTime == null){
      return null;
    }
    //返回的时间样式,需要自行补0
    String hour = selectTime.hour.toString().padLeft(2,"0");
    String minute = selectTime.minute.toString().padLeft(2,"0");
    String timeStr = "$hour:$minute:00";
    return timeStr;
  }
//TODO: 选择循环提醒类型
Future<int> showSelectType(BuildContext context) async{
  int? i = await showDialog<int>(
      context: context,
      builder: (BuildContext context){
        return SimpleDialog(
          alignment: Alignment.center,
          title: Text(SSLLocales.l_dream_cycle.tr),
          children: [
            SimpleDialogOption(
              onPressed: (){
                cycleType = 1;
                warningTypeStr = SSLLocales.l_dream_cycle_everyDay.tr;
                Get.back(result: 1);
              },
              child: Text(SSLLocales.l_dream_cycle_everyDay.tr),
            ),
           ... 重复,数据不同
          ],
        );
      }
  );
  //字符串显示转换,讲值转换成对应的字符串
  warningCycleTimeStr = getDefaultCycleString();
  return i ?? -1;
}

build中的代码展示:

@override
Widget build(BuildContext context) {
  // TODO: implement build
  return GestureDetector(
    onTap: (){
      debugPrint("ssl tap show time\n");//为什么不放下一层,Flutter的机制是仅有内容的区域才可响应手势,放下层无内容点击不响应
      FocusScope.of(context).requestFocus(boardFocus);
    },
    child: Scaffold(
      appBar: AppBar(
        title: Text(SSLLocales.l_dream_name.tr),
        leading: IconButton(
          icon: Icon(Icons.arrow_back, color: sslUI.iconLeftColor,),
          onPressed: (){
            Get.back(result: 0);
          },
        ),
        actions: [
          IconButton(onPressed: (){
            saveDreamAction();
          }, icon: Icon(Icons.save, color: sslUI.iconColor,))
        ],
      ),
      body: Column(
        children: [//标题输入
          SSLInputRow(
            style: SSLInputStyle.text,
            title: SSLLocales.l_dream_name.tr,
            inputText: dreamNameStr,
            tag: 1,
            callback: (tag, v){
              debugPrint("ssl tap $tag $v");
              dreamNameStr = v;
            },
          ),//开关选项封装
          SSLSwitchRowCell(
              title: SSLLocales.l_dream_cycle_isWarning.tr,
              isOn: isWarning,
              valueChanged: (v){
                isWarning = v;
            },
          ),//类型选择
          SSLInputRow(
            inputText: warningTypeStr,
            style: SSLInputStyle.arrow,
            title: SSLLocales.l_dream_cycle.tr,
            onTap: () async {
              debugPrint("ssl tap show time picker 0$warningTypeStr\n");
              int cycle = await showSelectType(context);
              setState(() {

              });
            },
          ),
          showCycleWidget(),//根据选择类型判断是否隐藏时间选项
          SSLInputRow(
            inputText: warningTimeStr,
            style: SSLInputStyle.arrow,
            title: SSLLocales.l_dream_time.tr,
            onTap: () async {
              String nowDay = SSLEngine.dateTimeYearString(DateTime.now());
              //这里讲字符串转换为时间,需要注意的是字符串格式不要错了,否则会转换失败返回nil
              DateTime curTime = DateTime.parse("$nowDay $warningTimeStr");
              String? timeStr = await showDefaultTimePicker(context, curTime);
              if (timeStr != null){
                setState(() {
                  warningTimeStr = timeStr;
                  debugPrint("ssl tap show time picker $warningTimeStr\n");

                });
              }
            },
          ),
          const Padding(padding: EdgeInsets.only(top: 1)),
          //下面的输入框
          Container(//先用Container包裹,展示背景色
            height: 200,
            color: sslUI.cellBackColor,
            child: Padding(//Padding设置边距
                padding: const EdgeInsets.only(left: 15,right: 15,top: 15,bottom: 15),
                child:ClipRRect(//切圆角
                  borderRadius: BorderRadius.circular(8),
                  child: Container(//改变输入背景色
                      color: sslUI.cellSubBackColor,
                      child:TextField(//具体输入的控件
                        controller: textControl,
                        textAlign: TextAlign.start,
                        style: TextStyle(color: sslUI.subText),
                        keyboardType: TextInputType.multiline,
                        maxLines: null,
                        decoration: InputDecoration(//装饰器,添加输入提示语
                            hintText: SSLLocales.l_input_placeholder.tr + SSLLocales.l_dream_describe.tr,
                            border: InputBorder.none,
                            fillColor: sslUI.cellBackColor
                        ),
                        onChanged: (v){//输入文字回调
                          describeStr = v;
                        },
                      ),
                  ),
                ),
            ),
          ),
        ],
      ),
    ),
  );
}

最后是保存功能

void saveDreamAction() async{
//获取当前时间戳
  int createTimestamp = DateTime.now().millisecondsSinceEpoch;
  if (dreamId.isEmpty){//判断是新增还是修改
    Map<String, dynamic> data = {//新增则创建DreamID
      "dreamId" : SSLEngine.createDreamId(),
      "title" : dreamNameStr,
      "cycleType" : cycleType,
      "cycleTime" : cycleTime,
      "time" : warningTimeStr,
      "subTitle" : describeStr,
      "createTime" : createTimestamp,
      "lastTime" : createTimestamp,
      "type" : 1,
      "isWarning" : isWarning,
    };
    int result = 0;
    if (isWarning){//新增如果开启提醒则设置系统闹钟
    //系统闹钟数据格式
      Map<String, dynamic> info = {
        "identify":data["dreamId"],
        "time":data["warningTimeStr"],
        "type":data["cycleType"],
        "repeatTime":data["cycleTime"],
        "isRepeat":true,
        "title":data["title"],
        "body":data["subTitle"],
        "isOpen" :  isWarning
      };
      //设置系统闹钟
      result = await setAlarmClockAction(info);
      if (result < 0){

      }
    }
    //插入数据库
    sslDB.insertDream(data, (int id, String value){
      debugPrint("ssl create dream $id  $data");
      if (id > 0){
      //弹窗
        Fluttertoast.showToast(msg: SSLLocales.l_toast_dream_add.tr);
        Get.back(result: id);
      }else{
        //error
      }
    });
  }else{
  //修改数据,传入之前的dreamId
    Map data = {
      "dreamId" : dreamId,
      "title" : dreamNameStr,
      "cycleType" : cycleType,
      "cycleTime" : cycleTime,
      "time" : warningTimeStr,
      "subTitle" : describeStr,
      "createTime" : createTimestamp,
      "lastTime" : createTimestamp,
      "type" : 1,
      "isWarning" : isWarning,
    };
    int result = 0;
    Map<String, dynamic> info = {
      "identify":data["dreamId"],
      "time":data["warningTimeStr"],
      "type":data["cycleType"],
      "repeatTime":data["cycleTime"],
      "isRepeat":true,
      "title":data["title"],
      "body":data["subTitle"],
      "isOpen" :  isWarning
    };
    //判断是关闭还是打开闹钟
    result = await setAlarmClockAction(info);
    if (result < 0){
    //error,比如没通知权限或者其他原因
    }
    //更新数据库
    int count = await sslDB.updateDream(data);
    if (count > 0){
      DreamModel? dream = await sslDB.selectDreamById(dreamId);
      if (dream != null){
      //弹窗
        Fluttertoast.showToast(msg: SSLLocales.l_toast_dream_update.tr);
        Get.back(result: dream);
      }
    }else{
    //error
    }
  }
}

以上就是全部的实现逻辑了,欢迎指正。