게시판 답변

10 글 보임 - 1 에서 10 까지 (총 54 중에서)
  • 글쓴이
  • 답변: 비공개: [wordpress] astra에서 view count #16688
    mimoon
    키 마스터

      2024-05-04 update: 30이하일 때 배경색 띠 삭제를 위해

      
      /***2024-05-04 for jp_post_view count */
      $jp_post_view_astra = do_shortcode( '' );
      if (strpos($jp_post_view_astra,'👁')) { 
         echo "<span style='padding-right: 2px;' id='view_count' class='highlight'>&nbsp;".$jp_post_view_astra."&nbsp;</span><br>";
      } else {
         echo "";
      }
      /***2024-05-04 End of jp_post_view count */
      
      답변: 비공개: [wordpress] astra에서 view count #16646
      mimoon
      키 마스터

        2024-03-27 change code according to astra theme
        함수명이나 구조가 완전히 달라짐
        파일 구도는 그대로 \astra\Inc\blog\blog.php
        그러나 Line 571~582 쯤 다음 부분에 삽입

        
        case 'single-meta':
          do_action( 'astra_single_post_banner_meta_before' );
          $post_meta = astra_get_option( 'ast-dynamic-single-' . $post_type . '-metadata', array( 'comments', 'author', 'date' ) );
          $output    = '';
          if ( ! empty( $post_meta ) ) {
            $output_str = astra_get_post_meta( $post_meta, '/', 'single-post' );
                if ( ! empty( $output_str ) ) {
                    $output = apply_filters( 'astra_single_post_meta', '<div class="entry-meta">' . $output_str . '</div>' ); // WPCS: XSS OK.
                }
           }
        
          /***2024-03-27 for jp_post_view count */
          $jp_post_view_astra = do_shortcode( '' );
          echo "<br><span style='padding: 0 1px 0 2px;' id='view_count' class='highlight'>&nbsp;".$jp_post_view_astra."&nbsp;</span><br>";
           /***2024-03-27 End of jp_post_view count */
        
           echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
           do_action( 'astra_single_post_banner_meta_after' );
        break;
        

        ‘echo $output;’의 바로 앞 줄

        답변: 비공개: [wordpress] astra에서 view count #15960
        mimoon
        키 마스터

          post-views-for-jetpack 플러그인의
          functions.jp-post-views.php 파일 내에
          다음 두 라인과

          
          $num_s = preg_replace("/[^0-9]*/s", "", $views['total']);
          if ( $num_s < 30 ) { return; }
          

          다음 라인

          
          '%s view',
          ' 👁 %s'.'명의 독자가 공감하셨습니다',
          

          이 둘을 추가/변경하지 않으면 단순 View(s)로만 게시
          전자는 30회 이하는 안 보여주는 코드.

          답변: 비공개: [wordpress] astra에서 view count #15944
          mimoon
          키 마스터

            최신

            
            <!-- .post view count -->
            <span id='view_count' class="highlight"><?php echo do_shortcode( '' ); ?></span>
            <!-- .post view count end -->
            
            답변: 비공개: [Kotlin] DiffUtil 성공 #15500
            mimoon
            키 마스터

              현재 이 시간 성공한 RoombibleAdapter

              
              
              class RoombibleAdapter : RecyclerView.Adapter<RoombibleAdapter.Holder>(){
              //class RoombibleAdapter : RecyclerView.Adapter<RoombibleAdapter.ArticleViewHolder>(){
              //class RoombibleAdapter : ListAdapter<RoomPbible, RoombibleAdapter.Holder>(DiffUtils) {
              
                  var helper:RoomHelper? = null
                  var bibleData = mutableListOf<RoomPbible>()
                  var selectedExpense = arrayListOf<RoomPbible>()
              
                  /*
                  private val differCallback = object: DiffUtil.ItemCallback<RoomPbible>(){
                      // 이함수는 oldItem과 new Item이 같은지 확인하는 함수입니다.
                      override fun areItemsTheSame(oldItem: RoomPbible, newItem: RoomPbible): Boolean {
                          // oldItem과 newItem은 전에 만들었던 article dataclass의 타입을 가지고있음
                          // 같은아이템인지 확인하려면 두 아이템에 고유ID를 확인해줘야
                          // 기사마자 다른 url을 가지고있기때문에 data class에서 각 아이템의 url을 확인
                          return oldItem.rhv == newItem.rhv
                      }
                      @SuppressLint("DiffUtilEquals")
                      override fun areContentsTheSame(oldItem: RoomPbible, newItem: RoomPbible): Boolean {
                          //둘의 컨텐츠도 비교해줍니다.
                          return oldItem == newItem
                      }
                  }
                  */
              
                  // 2021-12-01 Original
                  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RoombibleAdapter.Holder {
                      val roombibleBinding = ItemRoombibleBinding.inflate(LayoutInflater.from(parent.context), parent, false)
                      return Holder(roombibleBinding)
                  }
              
                  /*
                  // 2021-12-02 Expense에서 온 것
                  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
                      Holder(ItemRoombibleBinding.inflate(LayoutInflater.from(parent.context), parent, false))
                   */
              
                  inner class Holder(private val roombibleBinding: ItemRoombibleBinding) : RecyclerView.ViewHolder(roombibleBinding.root) {
                      private var mRoomBible:RoomPbible? = null
              
                      /*
                      fun bind(roombible: RoomPbible) {
                          with(roombibleBinding) {
                              bibleContent.text = roombible.rhv
                              bibleCompare.text = roombible.cmv
                          }
                      }
                      */
              
                      fun setRoomBible(roombible:RoomPbible) {
                          //binding.textNo.text = "${memo.no}"
                          //val str1 = roombible.rhv
                          //val trimRhv = str1.replace("[0-9\\:]".toRegex(), "")
                          //val str2 = roombible.cmv
                          //val trimCmv = str2.replace("[0-9\\:]".toRegex(), "")
                          roombibleBinding.bibleContent.text = roombible.rhv  //trimRhv
                          roombibleBinding.bibleCompare.text = roombible.cmv  //trimCmv
                          //val sdf = SimpleDateFormat("yy/MM/dd hh:mm")
                          // 날짜 포맷은 SimpleDateFormat으로 설정합니다.
                          //roombibleBinding.textDatetime.text = sdf.format(roombible.datetime)
              
                          this.mRoomBible = roombible
                      }
              
                  }
              
                  override fun getItemCount(): Int {
                      return bibleData.size
                  }
              
                  override fun getItemViewType(position: Int): Int {
                      return position % 2
                  }
              
                  override fun getItemId(position: Int): Long {
                      //val product: Product = bibleData[position]
                      //return product.pid
                      return position.toLong()
                  }
              
                  // 2021-12-01 Original에 Expense와 또 하나 섞은 것
                  override fun onBindViewHolder(holder: RoombibleAdapter.Holder, position: Int) {
                      val roombible = bibleData[position]
                      holder.setRoomBible(roombible)
              
                      // 2021-12-01 실패
                      /*
                      val article = differ.currentList[position]
                      //각 리스트의 구성요소들을 UI에 연결
                      holder.itemView.apply{
                          //val bibleCompare = g.
                           = article.rhv
                          bibleCompare.text = article.cmv
                          // 각 항목 클릭 가능하게
                          setOnClickListener{
                              onItemClickListener?.let{
                                  it(article)
                              }
                          }
                      }
                      */
              
                      // holder.bind(getItem(position))   //2021-12-02 Expense에서 온 것
              
                  }
              
                  companion object DiffUtils : DiffUtil.ItemCallback<RoomPbible>() {
                      override fun areItemsTheSame(oldItem: RoomPbible, newItem: RoomPbible): Boolean {
                          return oldItem.rhv == newItem.rhv
                      }
                      @SuppressLint("DiffUtilEquals")
                      override fun areContentsTheSame(oldItem: RoomPbible, newItem: RoomPbible): Boolean {
                          return oldItem == newItem
                      }
                  }
              
                  private var onItemClickListener: ((RoomPbible) -> Unit)? = null
              
                  fun setOnItemClickListener(listener: (RoomPbible) -> Unit) {
                      onItemClickListener = listener
                  }
              
                  // 2021-12-02
                  class DiffUtilCallback(
                      private val oldData: List<RoomPbible>,
                      private val newData: List<RoomPbible>
                  ) : DiffUtil.Callback() {
                      override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
                          val oldItem = oldData[oldItemPosition]
                          val newItem = newData[newItemPosition]
                          return oldItem.rhv == newItem.rhv
                          /*
                          return if (oldItem is Board && newItem is Board) {
                              oldItem.rhv == newItem.rhv
                          } else {
                              false
                          }
                          */
                      }
                      override fun getOldListSize(): Int = oldData.size
                      override fun getNewListSize(): Int = newData.size
                      override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
                          oldData[oldItemPosition] == newData[newItemPosition]
                  }
              
                  /*
                  class DiffUtilCallback(
                      private val oldData: List<RoomPbible>,
                      private val newData: List<RoomPbible>
                  ) : DiffUtil.Callback() {
                      override fun areItemsTheSame(oldData: RoomPbible, newData: RoomPbible): Boolean {
                          return oldData.rhv == newData.rhv
                      }
                      override fun getOldListSize(): Int = oldData.size
                      override fun getNewListSize(): Int = newData.size
                      override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
                          TODO("Not yet implemented")
                      }
                      override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
                          oldData[oldItemPosition] == newData[newItemPosition]
                  }
                  */
              
                  /*
                  // 2021-12-01    보류
                  //viewholder를 만들어줌
                  //inner class ArticleViewHolder(itemView: View): RecyclerView.ViewHolder(itemView)
                  inner class ArticleViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
                      var bibleContent : TextView = itemView.findViewById(R.id.bibleContent)
                      var bibleCompare : TextView = itemView.findViewById(R.id.bibleCompare)
                  }
                  */
              
                  //추가시작  2021-12-01
                  //val differ = AsyncListDiffer(this, differCallback)    // 앞의 것에 달린 것
                  /*
                  override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) {
                      val article = differ.currentList[position]
                      holder.itemView.apply { // apply: reference views directly
                          holder.bibleContent.text = article.rhv
                          holder.bibleCompare.text = article.cmv
                          setOnClickListener { onItemClickListener?.let { it(article) } }
                      }
                  }
                  */
                  /*
                   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder {
                      return ArticleViewHolder(
                          LayoutInflater.from(parent.context).inflate(R.layout.item_roombible, parent,false)
                      )
                  }
                  */
              
                  /*
                  override fun getItemCount(): Int {
                      //리사이클러뷰에서는 보통 리스트를 받아서 그 리스트 사이즈를 count하지만 리스트를 asynclistdiffer가 관리하기때문에, differ에 item갯수로 연결해주어야합니다.
                      return differ.currentList.size
                  }
                  //추가끝
                  */
              
                  /*
                  override fun submitList(list: List<Item>?) {
                      super.submitList(list)
                  }
                  */
              
                  fun removeSelectedExpense() = bibleData.clear()
                  //fun selectBibleSize() = differ.currentList.size
                  fun removeSelectedExpense2() {
                      bibleData.clear()
                      notifyDataSetChanged()
                      //notifyItemRangeRemoved(0, itemCount)
                  }
                  fun unselectBibleData() {
                      val sizex = bibleData.size
                      val handler = Handler(Looper.getMainLooper())
                      Log.d("Room of pentalogia", "선택사이즈 A: $sizex B: $itemCount")
                      handler.postDelayed({
                          //CoroutineScope(Dispatchers.IO).launch{
                          for (i in 0 until 30) {
                              val sizey= bibleData[i].rhv
                              //bibleData.removeAt(i)
                              //if(i%2 ==1) {
                                  Log.d("Room of pentalogia", "선택 $sizey")
                                  bibleData.removeAt(i)
                              //}
                          }
                          /*
                          for (i in bibleData.indices.reversed()) {
                              val sizey= bibleData[i].rhv
                              Log.d("Room of pentalogia", "선택 $sizey")
                              //if (bibleData[i].contains("bad")) {
                                  bibleData.removeAt(i)
                              //}
                          }
                          */
                         /*
                          val numberIterator = bibleData.iterator()
                          while (numberIterator.hasNext()) {
                              val integer = numberIterator.next()
                              if (integer < 3) {
                                  numberIterator.remove()
                              }
                          }
                          */
                          //}
                      },0)
                  }
              
                  fun refresh(data: List<RoomPbible>) {
                      //val selectedExpense: MutableList<RoomPbible> = mutableListOf()
                      /*
                      // 2021-12-02 Compleate!! Good. but lzay
                      bibleData.clear()
                      bibleData.addAll(data)
                      val handler = Handler(Looper.getMainLooper())
                      handler.postDelayed({
                          notifyDataSetChanged()
                      }, 0)
                      */
              
                      /*
                      val oldItem = RoombibleAdapter.areItemsTheSame()
                      //val diffCallback = differCallback(this.)
                      val result = DiffUtil.calculateDiff()
                      bibleData = data as MutableList<RoomPbible>
                      result.dispatchUpdatesTo(this)
                      */
                      val diffCallback = DiffUtilCallback(this.bibleData, data)
                      val diffResult = DiffUtil.calculateDiff(diffCallback)
                      bibleData.clear()
                      bibleData.addAll(data)
                      val handler = Handler(Looper.getMainLooper())
                      handler.postDelayed({
                          diffResult.dispatchUpdatesTo(this)
                      }, 0)
                  }
                  fun loadFakeData2() {
                      //rbAdapter.bibleData.addAll(helper?.roomPbibleDao()?.getAllPbible() ?: listOf())
                      selectedExpense.addAll(helper?.roomPbibleDao()?.getAllPbible() ?: listOf())
                  }
              
              }
              
              mimoon
              키 마스터

                //completed version
                // 성공

                
                // 2021-11-16
                    private fun startDownload() {
                        //if(Build.VERSION.SDK_INT >= 17){
                        //    val dbPATH = this.applicationInfo.dataDir+"/databases/"
                        //}else {
                            //this.DB_PATH = "/data/data/"+context.getPackageName()+"/databases/";
                            val dbPATH = "/data/data/" + applicationContext.packageName + "/databases/"
                            //Log.e("Path:", DB_PATH);
                        //}
                        val dbNAME = "room_memo.db"
                        val strOutFile = dbPATH + dbNAME
                        val request = DownloadManager.Request(Uri.parse("https://mimoonchurch.net/room_memo.db"))
                        request.setTitle("room_memo.db")
                        request.setDescription("My database is downloading.")
                        request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
                        //request.allowScanningByMediaScanner()
                        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
                        val filename: String =
                            URLUtil.guessFileName("https://mimoonchurch.net/room_memo.db", null, MimeTypeMap.getFileExtensionFromUrl("https://mimoonchurch.net/room_memo.db"))
                        request.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, filename)    // to save in cache
                        //request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename)      // to save in public download folder
                        //request.setDestinationInExternalPublicDir(Environment.getDownloadCacheDirectory().toString(), filename)
                        //val manager = getSystemService(DOWNLOAD_SERVICE) as DownloadManager   // to start download
                        //manager.enqueue(request)
                
                        // to test by written url
                        //val target = File(strOutFile)       // 에뮬레이터에서만 효용
                        val target = File(dbPATH, dbNAME)  // 에뮬레이터에서 효용
                        if (!target.exists()) {
                            gAlert("내부 저장소(수동 경로 $target)에 파일이 없음을 확인했습니다.")
                            //target.createNewFile()
                        } else {
                            val dbSize: Int = java.lang.String.valueOf(target.length() / 1024).toInt()
                            gAlert("내부 저장소(수동 경로 $target)에 파일(크기: $dbSize)이 이미 존재합니다.")
                            //target.delete()
                            //target.createNewFile()
                            //val manager =  getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
                            //manager.enqueue(request)
                        }
                
                        //val currentDBPath = "\\data\\com.w_13567767\\databases\\room_memo.db"
                        val currentDBPath = "/data/data/" + applicationContext.packageName + "/databases/"
                        val currentGetDbPath: File = this.getDatabasePath("room_memo.db")     // 파일 명 포함
                        val outFileName = currentGetDbPath.path
                        //val downloadFolder = File(cacheDir.toString())
                        val downloadFolder = File(Environment.DIRECTORY_DOWNLOADS).toString()
                        //val downloadFolder = Environment.getExternalStorageDirectory()  // 에뮬레이터에서 효용
                        val dataGetExternalStorageDirectory: File = Environment.getExternalStorageDirectory()      // 에뮬레이터에서 효용
                        val dataInternalGetDataDirectory: File = Environment.getDataDirectory()
                        val dataGetDirDnld: File = File(Environment.DIRECTORY_DOWNLOADS)
                        val dataGetDnldCacheDirectory: File = Environment.getDownloadCacheDirectory()
                        val dataDownloadFilesDir = this.filesDir   // 내부 저장소 일반 파일
                        val dataDownloadCacheDir = this.cacheDir
                        val dataDirDnldGetExternalFilesDir = this.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
                        val dataDirDnldExternalStoragePublicDirectory = getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
                        //val dataDirDnld = this.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)
                        //val dataDirDnld = this.getDatabasePath(Environment.DIRECTORY_DOWNLOADS)
                        //val dataDirDnld = File(Environment.DIRECTORY_DOWNLOADS).toString()
                        //val data: File = File(cacheDir.toString())
                        //val currentDB = File(currentDBPath)
                        val backupDB = File(downloadFolder, dbNAME)
                        //val strOutFile2 = "$currentDBPath"
                        //gAlert("내부 저장소 절대경로는$strOutFile2")
                
                        //val target2 = File(strOutFile2)     // 에뮬과 디바이스 모두 안 됨
                        //val target2 = File(currentDBPath)       // 에뮬과 디바이스 모두 됨 (시스템에 의한 절대 경로 얻기)
                       // val target2 = File(outFileName)     // 에뮬레이터에서는 되고 디바이스에서는 안 됨
                        //val target2 = Environment.getDataDirectory()        // 에뮬레이터와 디바이스 모두 효용// 이것은 다운로드 폴더 경로
                        val target2 = File(currentGetDbPath.toString())    // 에뮬레이터에서 됨
                
                        val target3 = File(downloadFolder, dbNAME)        // 에뮬레이터에서만 효용
                        val targetGetExternalStorageDirectory = File(dataGetExternalStorageDirectory, dbNAME)      // 외장 다운로드 메모리 경로
                        val targetInternalGetDataDirectory = File(dataInternalGetDataDirectory, dbNAME)      // 내장 메모리 다운로드 폴더 경로
                        val targetDirectDownload = File(dataGetDirDnld, dbNAME)      // 내장 다운로드 메모리 경로
                        val targetGetDownloadCacheDirectory = File(dataGetDnldCacheDirectory, dbNAME)        // 에뮬에서 효용
                        val targetDownloadFilesDir = File(dataDownloadFilesDir, dbNAME)
                        val targetDownloadCacheDir = File(dataDownloadCacheDir, dbNAME)
                        val targetDirGetExternalFilesDir = File(dataDirDnldGetExternalFilesDir, dbNAME)
                        val targetDirDnldExternalStoragePublicDirectory = File(dataDirDnldExternalStoragePublicDirectory, dbNAME)
                        //val strOutFile3 = "$data/$backupDBPath"
                        //val target3 = File(strOutFile3)
                        //gAlert("공용 저장소 파일 절대경로는 $target3")
                        //gAlert("내부 저장소 절대경로는$target2")
                        if (target2.exists()) {
                            val dbSize: Int = java.lang.String.valueOf(target2.length() / 1024).toInt()
                            gAlert("내장 폴더 절대경로에서 파일(크기: $dbSize) 찾음. $target2")
                            //target.delete()
                            //target.createNewFile()
                            //Log.d("TAG", "==== backUpExists: " + "내장 폴더에서 백업파일 찾음");
                        } else {
                            gAlert("내장 폴더 절대경로에서 파일 못 찾음. $target2")
                
                        }
                        when {
                            targetGetExternalStorageDirectory.exists() -> {
                                gAlert("외부 저장소getExternalStorageDirectory($targetGetExternalStorageDirectory)에서 파일 찾음.")
                                targetGetExternalStorageDirectory.delete()
                                //targetGetExternalStorageDirectory.createNewFile()
                                //Log.d("TAG", "==== backUpExists: " + "다운로드 폴더에서 백업파일 찾음");
                            }
                            targetInternalGetDataDirectory.exists() -> {
                                gAlert("내부 저장소getDataDirectory($targetInternalGetDataDirectory)에서 파일 찾음.")
                                targetInternalGetDataDirectory.delete()
                            }
                            targetDirectDownload.exists() -> {
                                gAlert("다운로드 지정했던 함수DIRECTORY_DOWNLOADS($targetDirectDownload)에서 파일 찾음.")
                                targetDirectDownload.delete()
                            }
                            targetGetDownloadCacheDirectory.exists() -> {
                                gAlert("getDownloadCacheDirectory($targetGetDownloadCacheDirectory)에서 파일 찾음.")
                                targetGetDownloadCacheDirectory.delete()
                            }
                            targetDownloadFilesDir.exists() -> {
                                val dbSize: Int = java.lang.String.valueOf(targetDownloadFilesDir.length() / 1024).toInt()
                                gAlert("내부 저장소 FilesDir($targetDownloadFilesDir)에서 파일(크기: $dbSize) 찾음.")
                                //targetDownloadFilesDir.delete()
                            }
                            targetDownloadCacheDir.exists() -> {
                                gAlert("내부 저장소 CacheDir($targetDownloadCacheDir)에서 파일 찾음.")
                                targetDownloadCacheDir.delete()
                            }
                            targetDirGetExternalFilesDir.exists() -> {
                                val dbSize: Int = java.lang.String.valueOf(targetDirGetExternalFilesDir.length() / 1024).toInt()
                                gAlert("외부저장소 DirGetExternalFilesDir ($targetDirGetExternalFilesDir)에서 파일(크기: $dbSize) 찾음.")
                                //targetDirGetExternalFilesDir.delete()
                            }
                            targetDirDnldExternalStoragePublicDirectory.exists() -> {
                                val dbSize: Int = java.lang.String.valueOf(targetDirDnldExternalStoragePublicDirectory.length() / 1024).toInt()
                                gAlert("외부 저장소 DirDnldExternalStoragePublicDirectory($targetDirDnldExternalStoragePublicDirectory)에서 파일(크기: $dbSize) 찾음.")
                                //targetDirDnldExternalStoragePublicDirectory.delete()
                            }
                            target3.exists() -> {
                                gAlert("File(Environment.DIRECTORY_DOWNLOADS)($target3)에서 파일 찾음.")
                                target3.delete()
                            }
                            else -> {
                                gAlert("아무 곳에서도 파일  못 찾음.")
                                val manager =  getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
                                manager.enqueue(request)
                
                            }
                        }
                        /*
                        val src: FileChannel = FileInputStream(currentDB).channel
                        val dst: FileChannel = FileOutputStream(backupDB).channel
                        dst.transferFrom(src, 0, src.size())
                        src.close()
                        dst.close()
                        */
                
                        // 2021-11-20
                        // Make sure we have a path to the file
                        //currentGetDbPath.getParentFile().mkdirs()
                        // Try to copy database file
                        /* Try 부분을 제거해도 이전 가능
                        try {
                            val inputStream: InputStream = targetDirGetExternalFilesDir.inputStream()       // 작동
                            //val inputStream: InputStream = currentGetDbPath.inputStream()
                            //val inputStream: InputStream = getDatabasePath("room_memo.db").inputStream()
                            val output: OutputStream = FileOutputStream(currentGetDbPath)
                            //val output: OutputStream = FileOutputStream(getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS))
                            //val output: OutputStream = FileOutputStream(targetDirDnldExternalStoragePublicDirectory)
                            //val output: OutputStream = FileOutputStream(targetDownloadFilesDir)     // 작동
                            //val buffer = ByteArray(8192)
                            val buffer = ByteArray(1024)
                            var length: Int
                            while (inputStream.read(buffer, 0, 1024).also { length = it } > 0) {
                                output.write(buffer, 0, length)
                            }
                            output.flush()
                            output.close()
                            inputStream.close()
                
                            //val src: FileChannel = FileInputStream(currentGetDbPath).channel
                            //val dst: FileChannel = FileOutputStream(targetDirDnldExternalStoragePublicDirectory).channel
                            //dst.transferFrom(src, 0, src.size())
                            //src.close()
                            //dst.close()
                
                        } catch (e: IOException) {
                            Log.d("pentalogia", "Failed to open file", e)
                            e.printStackTrace()
                            //gAlert("복사 실패")
                        }
                
                        //Try를 제거해도 createFromFile이 수행
                        */ 
                
                        lifecycleScope.launch(Dispatchers.IO) {
                            //.allowMainThreadQueries()
                            // 2021-11-07
                            //rcAdapter.setHasStableIds(true)
                            withContext(Dispatchers.IO) {
                                helper =
                                    Room.databaseBuilder(this@ListviewActivity, RoomHelper::class.java, "room_memo")
                                        .addMigrations(MigrateDatabase.MIGRATE_1_2)
                                        // 2021-11-16
                                        .createFromFile(File(targetDirGetExternalFilesDir.toString()))
                                              .fallbackToDestructiveMigration()
                                        //.allowMainThreadQueries()
                                        .build()
                                rcAdapter.helper = helper
                                rcAdapter.listData.addAll(helper?.roomMemoDao()?.getAll() ?: listOf())
                            }
                            laBinding.recyclerMemo.adapter = rcAdapter
                            laBinding.recyclerMemo.layoutManager = LinearLayoutManager(this@ListviewActivity)
                
                            // VerticalItemDecorator
                            //laBinding.recyclerMemo.addItemDecoration(VerticalItemDecorator(10))
                            //laBinding.recyclerMemo.addItemDecoration(DividerItemDecoration(this, LinearLayoutManager.VERTICAL))
                
                            // 2021-11-09 VerticalItemDecorator kill
                            /*
                            val decoDevider = CustomDecoration(3f, 10f, Color.LTGRAY)
                            laBinding.recyclerMemo.addItemDecoration(decoDevider)
                            */
                
                            (laBinding.recyclerMemo.layoutManager as LinearLayoutManager).reverseLayout = true
                            (laBinding.recyclerMemo.layoutManager as LinearLayoutManager).stackFromEnd = true
                            // if empty any data
                            val emptyView: TextView = laBinding.emptyView
                            if (rcAdapter.itemCount == 0) emptyView.visibility =
                                View.VISIBLE else emptyView.visibility = View.GONE
                            rcAdapter.notifyDataSetChanged()
                        }
                
                    }
                
                mimoon
                키 마스터

                  last

                  
                  private fun startDownload() {
                          val dbPATH = "/data/data/" + applicationContext.packageName + "/databases/"
                          val dbNAME = "room_memo.db"
                          val strOutFile = dbPATH + dbNAME
                          /*
                          val request = DownloadManager.Request(Uri.parse("https://mimoonchurch.net/room_memo.db"))
                          request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE)
                          request.setTitle("room_memo.db")
                          request.setDescription("My database is downloading.")
                          request.allowScanningByMediaScanner()
                          request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
                          request.setDestinationInExternalPublicDir(dbPATH, "room_memo.db")
                          val manager =  getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
                          manager.enqueue(request)
                          */
                          val request = DownloadManager.Request(Uri.parse("https://mimoonchurch.net/room_memo.db"))
                          request.setTitle("room_memo.db")
                          request.setDescription("My database is downloading.")
                          request.allowScanningByMediaScanner()
                          request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
                          val filename: String =
                              URLUtil.guessFileName("https://mimoonchurch.net/room_memo.db", null, MimeTypeMap.getFileExtensionFromUrl("https://mimoonchurch.net/room_memo.db"))
                          request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename)
                          //request.setDestinationInExternalPublicDir(dbPATH, filename)
                          //val manager = getSystemService(DOWNLOAD_SERVICE) as DownloadManager
                          //manager.enqueue(request)
                  
                          val target = File(strOutFile)
                          if (!target.exists()) {
                              gAlert("내부 저장소($strOutFile)에 파일이 없음을 확인했습니다.")
                              target.createNewFile()
                          } else {
                              gAlert("내부 저장소($strOutFile)에 파일이 이미 존재합니다.")
                              target.delete()
                              target.createNewFile()
                              val manager =  getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
                              manager.enqueue(request)
                          }
                  
                          //val currentDBPath = "\\data\\com.w_13567767\\databases\\room_memo.db"
                          //val currentDBPath = "/data/data/" + applicationContext.packageName + "/databases/"
                          val backupDBPath = "room_memo.db"
                          val currentDBPath2: File = this.getDatabasePath("room_memo.db")
                          val outFileName = currentDBPath2.path
                          val downloadFolder = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString())
                          //val downloadFolder = File(Environment.DIRECTORY_DOWNLOADS).toString()
                          val data: File = Environment.getDataDirectory()
                          //val currentDB = File(currentDBPath)
                          val backupDB = File(downloadFolder, backupDBPath)
                          //val strOutFile2 = "$currentDBPath"
                          //gAlert("내부 저장소 절대경로는$strOutFile2")
                          //val target2 = File(strOutFile2)
                          val target2 = File(currentDBPath2, outFileName)
                          val currentDB = File(currentDBPath2.toString())
                          //val target3 = File(downloadFolder, backupDBPath)
                          val strOutFile3 = "$data/$backupDBPath"
                          val target3 = File(strOutFile3)
                          gAlert("공용 저장소 절대경로는$strOutFile3")
                          if(target2.exists()){
                              gAlert("내장 폴더에서 백업파일 찾음.")
                              target.delete()
                              target.createNewFile()
                              //Log.d("TAG", "==== backUpExists: " + "내장 폴더에서 백업파일 찾음");
                          }
                          if(target3.exists()){
                              gAlert("다운로드 폴더에서 파일 찾음.")
                              target.delete()
                              target.createNewFile()
                              //Log.d("TAG", "==== backUpExists: " + "다운로드 폴더에서 백업파일 찾음");
                          }
                          val src: FileChannel = FileInputStream(currentDB).channel
                          val dst: FileChannel = FileOutputStream(backupDB).channel
                          dst.transferFrom(src, 0, src.size())
                          src.close()
                          dst.close()
                  
                      }
                  
                  mimoon
                  키 마스터

                    에뮬에서는 잘 되지만, 디바이스에서는 crash

                    
                    /*
                            //val dbPATH = "/data/data/" + applicationContext.packageName + "/databases/"
                            val dbPATH : File = this.getDatabasePath("room_memo.db")
                            //val dbNAME = "room_memo.db"
                            val dbNAME = dbPATH.path
                            //val strOutFile = dbPATH + dbNAME
                            */
                            val request = DownloadManager.Request(Uri.parse("https://mimoonchurch.net/room_memo.db"))
                            request.setTitle("room_memo.db")
                            request.setDescription("My database is downloading.")
                            request.allowScanningByMediaScanner()
                            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
                            val filename: String =
                                URLUtil.guessFileName("https://mimoonchurch.net/room_memo.db", null, MimeTypeMap.getFileExtensionFromUrl("https://mimoonchurch.net/room_memo.db"))
                            request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename)
                            //request.setDestinationInExternalPublicDir(dbPATH, filename)
                            //val manager = getSystemService(DOWNLOAD_SERVICE) as DownloadManager
                            //manager.enqueue(request)
                    
                            /*
                            val target = File(dbPATH.toString())
                            if (!target.exists()) {
                                gAlert("내부 저장소(${target})에 파일이 없음을 확인했습니다.")
                                target.createNewFile()
                            } else {
                                gAlert("내부 저장소($target)에 파일이 이미 존재합니다.")
                                target.delete()
                                target.createNewFile()
                                val manager =  getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
                                manager.enqueue(request)
                            }
                            */
                    
                            //val currentDBPath = "\\data\\com.w_13567767\\databases\\room_memo.db"
                            //val currentDBPath = "/data/data/" + applicationContext.packageName + "/databases/"
                            val backupDBPath = "room_memo.db"
                            val currentDBPath2: File = this.getDatabasePath("room_memo.db")
                            val outFileName = currentDBPath2.path
                            val downloadFolder = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString())
                            //val downloadFolder = File(Environment.DIRECTORY_DOWNLOADS).toString()
                            val sd = Environment.getExternalStorageDirectory()
                            val data: File = Environment.getDataDirectory()
                            //val currentDB = File(currentDBPath)
                            //val backupDB = File(downloadFolder, backupDBPath)
                            val backupDB = File(sd, backupDBPath)
                            //val strOutFile2 = "$currentDBPath"
                            //gAlert("내부 저장소 절대경로는$strOutFile2")
                            //val target2 = File(strOutFile2)
                            val target2 = File(currentDBPath2, outFileName)
                            //val currentDB = File(currentDBPath2.toString())
                            val currentDB = File(sd, backupDBPath)
                            //val target3 = File(downloadFolder, backupDBPath)
                            val strOutFile3 = "$data/$backupDBPath"
                            val target3 = File(strOutFile3)
                            gAlert("공용 저장소 절대경로는$strOutFile3 가 아니라 $backupDB")
                            //val target = File(dbPATH.toString())
                            if (!currentDB.exists()) {
                                gAlert("내부 저장소(${currentDB})에 파일이 없음을 확인했습니다.")
                                currentDB.createNewFile()
                            } else {
                                gAlert("내부 저장소($currentDB)에 파일이 이미 존재합니다.")
                                currentDB.delete()
                                currentDB.createNewFile()
                                val manager =  getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
                                manager.enqueue(request)
                            }
                            if(currentDB.exists()){
                                gAlert("내장 폴더(${currentDB})에서 파일 찾음.")
                                currentDB.delete()
                                currentDB.createNewFile()
                                //Log.d("TAG", "==== backUpExists: " + "내장 폴더에서 백업파일 찾음");
                            }
                            if(backupDB.exists()){
                                gAlert("다운로드 폴더(${backupDB})에서 파일 찾음.")
                                backupDB.delete()
                                backupDB.createNewFile()
                                //Log.d("TAG", "==== backUpExists: " + "다운로드 폴더에서 백업파일 찾음");
                            }
                            val src: FileChannel = FileInputStream(backupDB).channel
                            val dst: FileChannel = FileOutputStream(currentDB).channel
                            dst.transferFrom(src, 0, src.size())
                            src.close()
                            dst.close()
                    
                    mimoon
                    키 마스터

                      최신 수정 상태에서 no error version

                      
                      //val dbPATH = "/data/data/" + applicationContext.packageName + "/databases/"
                              val dbPATH : File = this.getDatabasePath("room_memo.db")
                              //val dbNAME = "room_memo.db"
                              val dbNAME = dbPATH.path
                              //val strOutFile = dbPATH + dbNAME
                              val request = DownloadManager.Request(Uri.parse("https://mimoonchurch.net/room_memo.db"))
                              request.setTitle("room_memo.db")
                              request.setDescription("My database is downloading.")
                              request.allowScanningByMediaScanner()
                              request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
                              val filename: String =
                                  URLUtil.guessFileName("https://mimoonchurch.net/room_memo.db", null, MimeTypeMap.getFileExtensionFromUrl("https://mimoonchurch.net/room_memo.db"))
                              request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename)
                              //request.setDestinationInExternalPublicDir(dbPATH, filename)
                              //val manager = getSystemService(DOWNLOAD_SERVICE) as DownloadManager
                              //manager.enqueue(request)
                      
                              val target = File(dbPATH.toString())
                              if (!target.exists()) {
                                  gAlert("내부 저장소(${target})에 파일이 없음을 확인했습니다.")
                                  target.createNewFile()
                              } else {
                                  gAlert("내부 저장소($target)에 파일이 이미 존재합니다.")
                                  target.delete()
                                  target.createNewFile()
                                  val manager =  getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
                                  manager.enqueue(request)
                              }
                      
                              //val currentDBPath = "\\data\\com.w_13567767\\databases\\room_memo.db"
                              //val currentDBPath = "/data/data/" + applicationContext.packageName + "/databases/"
                              val backupDBPath = "room_memo.db"
                              val currentDBPath2: File = this.getDatabasePath("room_memo.db")
                              val outFileName = currentDBPath2.path
                              val downloadFolder = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString())
                              //val downloadFolder = File(Environment.DIRECTORY_DOWNLOADS).toString()
                              val data: File = Environment.getDataDirectory()
                              //val currentDB = File(currentDBPath)
                              val backupDB = File(downloadFolder, backupDBPath)
                              //val strOutFile2 = "$currentDBPath"
                              //gAlert("내부 저장소 절대경로는$strOutFile2")
                              //val target2 = File(strOutFile2)
                              val target2 = File(currentDBPath2, outFileName)
                              val currentDB = File(currentDBPath2.toString())
                              //val target3 = File(downloadFolder, backupDBPath)
                              val strOutFile3 = "$data/$backupDBPath"
                              val target3 = File(strOutFile3)
                              gAlert("공용 저장소 절대경로는$strOutFile3")
                              if(target2.exists()){
                                  gAlert("내장 폴더에서 백업파일 찾음.")
                                  target.delete()
                                  target.createNewFile()
                                  //Log.d("TAG", "==== backUpExists: " + "내장 폴더에서 백업파일 찾음");
                              }
                              if(target3.exists()){
                                  gAlert("다운로드 폴더에서 파일 찾음.")
                                  target.delete()
                                  target.createNewFile()
                                  //Log.d("TAG", "==== backUpExists: " + "다운로드 폴더에서 백업파일 찾음");
                              }
                              val src: FileChannel = FileInputStream(currentDB).channel
                              val dst: FileChannel = FileOutputStream(backupDB).channel
                              dst.transferFrom(src, 0, src.size())
                              src.close()
                              dst.close()
                      
                      mimoon
                      키 마스터

                        시간 설정이 있는 30분 단위 알람

                        
                         // 시간 / 분 변수화를 통해 시각 필터링
                                val HOUR_TO_SHOW_PUSH = 18
                                val MINUTE_TO_SHOW_PUSH = 30
                                val calendar = Calendar.getInstance().apply {
                                    // 약정 시간 감안 무조건 30분 간격
                                    if (get(Calendar.HOUR_OF_DAY) <= HOUR_TO_SHOW_PUSH)  {
                                        //add(Calendar.DAY_OF_MONTH, 1)
                                        if (get(Calendar.MINUTE) <= MINUTE_TO_SHOW_PUSH)  {
                                            //set(Calendar.HOUR_OF_DAY, (System.currentTimeMillis() / (1000 * 60 * 60) % 24).toInt())
                                            //set(Calendar.HOUR_OF_DAY, HOUR_TO_SHOW_PUSH)
                                            set(Calendar.MINUTE, MINUTE_TO_SHOW_PUSH)
                                        } else {
                                            add(Calendar.HOUR_OF_DAY, 1)
                                            set(Calendar.MINUTE, 0)
                                        }
                                    } else {
                                        if (get(Calendar.MINUTE) <= MINUTE_TO_SHOW_PUSH)  {
                                            //set(Calendar.HOUR_OF_DAY, (System.currentTimeMillis() / (1000 * 60 * 60) % 24).toInt())
                                            //add(Calendar.HOUR_OF_DAY, 1)
                                            set(Calendar.MINUTE, MINUTE_TO_SHOW_PUSH)
                                        } else {
                                            add(Calendar.HOUR_OF_DAY, 1)
                                            set(Calendar.MINUTE, 0)
                                        }
                                    }
                                }
                                var timeDiffInMillis: Long = calendar.timeInMillis - System.currentTimeMillis()
                                //if (timeDiffInMillis <= 0 ){
                                    alarmMgr?.setInexactRepeating(
                                            AlarmManager.RTC_WAKEUP,
                                            calendar.timeInMillis,
                                            AlarmManager.INTERVAL_HALF_HOUR,
                                            alarmIntent
                                    )
                                //}
                                val t_dateFormat2 = SimpleDateFormat("yyyy-MM-dd kk:mm:ss E", Locale("ko", "KR"))
                                // 현재 시간을 dateFormat 에 선언한 형태의 String 으로 변환
                                var str_date2 = t_dateFormat2.format(System.currentTimeMillis())
                                var ma_cald = t_dateFormat2.format(calendar.timeInMillis)
                                val calc = (timeDiffInMillis / (1000 * 60) % 60)
                                Toast.makeText(this@MainActivity,"현재 시각은:" +str_date2 + "다음 알람은" + ma_cald + "까지이며" + timeDiffInMillis + "밀리언세컨 즉," + calc + "분 남았습니다.",Toast.LENGTH_LONG).show()
                                
                        
                      10 글 보임 - 1 에서 10 까지 (총 54 중에서)